package com.company;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.plaf.nimbus.State;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
class GeometryUtils {
static boolean areRectsIntersecting(Rectangle2D a, Rectangle2D b) {
return (a.getX() <= b.getX() + b.getWidth()) && (a.getX() + a.getWidth() >= b.getX()) &&
(a.getY() <= b.getY() + b.getHeight()) && (a.getY() + a.getHeight() >= b.getY());
}
static Rectangle2D getRectsIntersection(Rectangle2D a, Rectangle2D b) {
double x = Math.max(a.getX(), b.getX());
double y = Math.max(a.getY(), b.getY());
double width = Math.min(a.getX() + a.getWidth(), b.getX() + b.getWidth()) - Math.max(a.getX(), b.getX());
double height = Math.min(a.getY() + a.getHeight(), b.getY() + b.getHeight()) - Math.max(a.getY(), b.getY());
return new Rectangle2D.Double(x, y, width, height);
}
static float distanceBetween(GameObject a, GameObject b) {
return (float)Math.sqrt((a.getX() - b.getX()) * (a.getX() - b.getX()) +
(a.getY() - b.getY()) * (a.getY() - b.getY()));
}
}
class ResourcesManager {
private static ResourcesManager resourcesManager = new ResourcesManager();
private Map<String, Image> imagesMap = new HashMap<>();
public static ResourcesManager getInstance() {
return resourcesManager;
}
private ResourcesManager() {
}
public Image loadImage(String path) {
if (imagesMap.containsKey(path)) {
return imagesMap.get(path);
}
try {
Image image = ImageIO.read(new File(path));
imagesMap.put(path, image);
return image;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
class GameObject {
private float x;
private float y;
private float width;
private float height;
private boolean isStatic = false;
GameObject() {
}
public boolean isStatic() {
return isStatic;
}
public void setStatic(boolean isStatic) {
this.isStatic = isStatic;
}
public void setPosition(float x, float y) {
setX(x);
setY(y);
}
public void move(float x, float y) {
if (isStatic()) {
throw new RuntimeException();
}
this.x += x;
this.y += y;
}
public void setSize(float width, float height) {
setWidth(width);
setHeight(height);
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Rectangle2D getRect() {
return new Rectangle2D.Float(getX(), getY(), getWidth(), getHeight());
}
public void update(float delta) {
}
public void render(Graphics2D g) {
}
public void handleKeyPress(char keyChar) {
}
public void handleKeyRelease(char keyChar) {
}
}
class TexturedBlock extends GameObject {
private Image image;
TexturedBlock(Image image) {
this.image = image;
}
@Override
public void render(Graphics2D g) {
g.drawImage(image, (int) getX(), (int) getY(), (int) getWidth(), (int) getHeight(), null);
g.setColor(Color.BLACK);
// g.drawRect((int) getX(), (int) getY(), (int) getWidth(), (int) getHeight());
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
enum PlayerState {
Jump,
OnPlatform,
Falling,
NotAlive
}
class Player extends TexturedBlock {
private float direction = 0.0f;
private final float acceleration = 50.8f;
private float velocity = 0.0f;
PlayerState state = PlayerState.Falling;
private int scores = 0;
private ArrayList<Platform> platforms;
Player(ArrayList<Platform> platforms) {
super(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\png\\player.png"));
this.platforms = platforms;
}
boolean isOnPlatform() {
return state == PlayerState.OnPlatform;
}
void setAlive(boolean alive) {
if (alive) {
state = PlayerState.Falling;
} else {
state = PlayerState.NotAlive;
}
}
boolean isAlive() {
return state != PlayerState.NotAlive;
}
void setScores(int scores) {
this.scores = scores;
}
int getScores() {
return scores;
}
void increaseScores(int increase) {
scores += increase;
}
@Override
public void update(float delta) {
float speed = 300.0f;
move(delta * speed * direction, 0);
if (state != PlayerState.OnPlatform) {
velocity += acceleration * delta;
move(0, velocity);
}
// if (state == PlayerState.Falling) {
// state = PlayerState.Falling;
//// velocity = acceleration * 1.5f;
// }
boolean somePlatformIsFound = false;
for (Platform platform : platforms) {
if (GeometryUtils.areRectsIntersecting(getRect(), platform.getRect())) {
Rectangle2D intersection = GeometryUtils.getRectsIntersection(getRect(), platform.getRect());
if (intersection.getWidth() < intersection.getHeight()) {
move(-direction * (float) intersection.getWidth(), 0);
} else {
int pushingDirection = -1;
if (getY() < platform.getY() + platform.getHeight() && getY() > platform.getY()) {
pushingDirection = 1;
}
move(0, (float) intersection.getHeight() * pushingDirection);
}
if (intersection.getWidth() > 10) {
if (intersection.getY() + intersection.getHeight() < getY() + getHeight() / 2.0f) {
velocity = 0;
} else {
state = PlayerState.OnPlatform;
velocity = 0;
somePlatformIsFound = true;
}
}
}
}
if (!somePlatformIsFound) {
if (state == PlayerState.OnPlatform) {
state = PlayerState.Falling;
}
}
}
@Override
public void handleKeyPress(char keyChar) {
// w a s d
if (keyChar == 'd') {
direction = 1.0f;
} else if (keyChar == 'a') {
direction = -1.0f;
} else if (keyChar == ' ') {
if (state == PlayerState.OnPlatform) {
velocity = -acceleration * 0.4f;
state = PlayerState.Falling;
}
}
}
@Override
public void handleKeyRelease(char keyChar) {
if (keyChar == 'd' || keyChar == 'a') {
direction = 0.0f;
}
}
}
enum PlatformType {
Grass,
Wood
}
class Platform extends TexturedBlock {
Platform(PlatformType type) {
super(null);
Image image = null;
if (type == PlatformType.Grass) {
image = ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\grass_flat.png");
} else if (type == PlatformType.Wood) {
image = ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\wood.png");
}
setImage(image);
}
@Override
public void update(float delta) {
}
}
class Coin extends TexturedBlock {
Coin() {
super(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\coin.png"));
}
}
class Spike extends TexturedBlock {
Spike() {
super(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\spike_2.png"));
}
void setTriggered(boolean triggered) {
if (triggered) {
setImage(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\spike_1.png"));
}
else {
setImage(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\spike_2.png"));
}
}
}
enum GameState {
Loading,
GameActive,
GameOver,
GameWin
}
class Viewport extends JPanel {
private JFrame window;
private Random random = new Random();
private final ArrayList<GameObject> gameObjects = new ArrayList<>();
private final ArrayList<Platform> platforms = new ArrayList<>();
private final ArrayList<Coin> coins = new ArrayList<>();
private final ArrayList<Spike> spikes = new ArrayList<>();
private Player player;
private GameState gameState = GameState.Loading;
private Font gameWinFont = new Font("TimesRoman", Font.PLAIN, 82);
private Font gameOverFont = new Font("TimesRoman", Font.PLAIN, 82);
private Font restartFont = new Font("TimesRoman", Font.PLAIN, 30);
private Font scoresFont = new Font("TimesRoman", Font.PLAIN, 24);
public Viewport(JFrame window) {
this.window = window;
}
public void initializeGame() {
TexturedBlock background = new TexturedBlock(ResourcesManager.getInstance().loadImage("C:\\Users\\nikolai\\IdeaProjects\\untitled\\assets\\cloudy2.jpg"));
background.setPosition(0, 0);
background.setSize(getWidth(), getHeight());
background.setStatic(true);
gameObjects.add(background);
player = new Player(platforms);
player.setPosition(0.0f, 0.0f);
player.setSize(50.0f, 75.0f);
gameObjects.add(player);
// addPlatform(PlatformType.Grass, 10, 50, 50, 50);
// addPlatform(PlatformType.Grass, 10 + 50 * 1, 50, 50, 50);
// addPlatform(PlatformType.Grass, 10 + 50 * 2, 50, 50, 50);
// addPlatform(PlatformType.Grass, 10 + 50 * 3, 50, 50, 50);
addPlatform(PlatformType.Grass, 10, 200, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 1, 200, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 2, 200, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 3, 200, 50, 50);
addPlatform(PlatformType.Grass, 300, 100, 50, 50);
addPlatform(PlatformType.Grass, 300 + 50 * 1, 100, 50, 50);
addPlatform(PlatformType.Grass, 300 + 50 * 2, 100, 50, 50);
addPlatform(PlatformType.Grass, 300 + 50 * 3, 100, 50, 50);
for (int index = 0; index < 50; index++) {
addPlatform(PlatformType.Grass, 500 + 50 * index, 100, 50, 50);
}
addPlatform(PlatformType.Grass, 10 + 50 * 4, 200 + 70 * 1, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 5, 200 + 70 * 1, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 6, 200 + 70 * 1, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 7, 200 + 70 * 2, 50, 50);
addPlatform(PlatformType.Grass, 10 + 50 * 8, 200 + 70 * 2, 50, 50);
addCoin(10 + 50 * 7 + 20, 200 + 70 * 2 - 50, 25, 25);
addCoin(10 + 50 * 7 + 100, 200 + 70 * 2 - 50, 25, 25);
addCoin(10 + 50 * 7 + 150, 200 + 70 * 2 - 50, 25, 25);
addCoin(300 + 20, 100 - 45, 25, 25);
addCoin(300 + 70, 100 - 45, 25, 25);
addSpike(10 + 50 * 7 + 20, 200 + 70 * 2 - 25, 50, 25);
addSpike(400 + 50 * 2, 100 - 25, 50, 25);
addSpike(400 + 50 * 4, 100 - 25, 50, 25);
addSpike(400 + 50 * 7, 100 - 25, 50, 25);
gameState = GameState.GameActive;
}
public void deinitializeGame() {
player = null;
platforms.clear();
coins.clear();
spikes.clear();
gameObjects.clear();
}
private void locateObject(GameObject object, float x, float y, float width, float height) {
object.setPosition(x, y);
object.setSize(width, height);
}
private void addPlatform(PlatformType platformType, float x, float y, float width, float height) {
Platform platform = new Platform(platformType);
locateObject(platform, x, y, width, height);
gameObjects.add(platform);
platforms.add(platform);
}
private void addCoin(float x, float y, float width, float height) {
Coin coin = new Coin();
locateObject(coin, x, y, width, height);
gameObjects.add(coin);
coins.add(coin);
}
private void addSpike(float x, float y, float width, float height) {
Spike spike = new Spike();
locateObject(spike, x, y, width, height);
gameObjects.add(spike);
spikes.add(spike);
}
public void handleKeyPress(KeyEvent event) {
if (gameState == GameState.GameOver || gameState == GameState.GameWin) {
switch (event.getExtendedKeyCode()) {
case KeyEvent.VK_ESCAPE:
deinitializeGame();
window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
break;
case KeyEvent.VK_R:
deinitializeGame();
initializeGame();
gameState = GameState.GameActive;
break;
default:
break;
}
} else {
for (GameObject object : gameObjects) {
object.handleKeyPress(event.getKeyChar());
}
}
repaint();
}
public void handleKeyRelease(KeyEvent event) {
for (GameObject object : gameObjects) {
object.handleKeyRelease(event.getKeyChar());
}
repaint();
}
public void updateGame(float delta) {
if (gameState == GameState.Loading) {
return;
}
if (gameState == GameState.GameActive) {
for (GameObject object : gameObjects) {
object.update(delta);
}
}
// Сборка монет
ArrayList<Coin> coinsToRemove = new ArrayList<>();
for (Coin coin : coins) {
if (GeometryUtils.areRectsIntersecting(player.getRect(), coin.getRect())) {
coinsToRemove.add(coin);
player.increaseScores(1);
}
}
for (Coin coin : coinsToRemove) {
coins.remove(coin);
gameObjects.remove(coin);
}
if (player.isOnPlatform()) {
for (Spike spike : spikes) {
spike.setTriggered(GeometryUtils.distanceBetween(player, spike) < 200.0f);
if (GeometryUtils.areRectsIntersecting(player.getRect(), spike.getRect())) {
player.setAlive(false);
break;
}
}
}
if (player.getY() > getHeight()) {
player.setAlive(false);
}
if (player.isAlive()) {
if (player.getX() < getWidth() / 4.0f || player.getX() + player.getWidth() >= getWidth() * (3.0f / 4.0f)) {
float movement = player.getX() < getWidth() / 4.0f ? getWidth() / 4.0f - player.getX() :
(getWidth() * (3.0f / 4.0f) - (player.getX() + player.getWidth()));
for (GameObject object : gameObjects) {
if (!object.isStatic()) {
object.move(movement, 0.0f);
}
}
}
}
if (!player.isAlive()) {
gameState = GameState.GameOver;
} else {
if (coins.isEmpty()) {
gameState = GameState.GameWin;
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (gameState == GameState.Loading) {
return;
}
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
for (GameObject object : gameObjects) {
object.render((Graphics2D) g);
}
// Рисуем GUI
if (gameState == GameState.GameOver) {
g.setFont(gameOverFont);
g.drawString("Game over!", 100, 100);
g.setFont(restartFont);
g.drawString("Press R to restart", 100, 150);
g.drawString("Press ESC to exit", 100, 180);
} else if (gameState == GameState.GameWin) {
g.setColor(Color.GREEN);
g.setFont(gameWinFont);
g.drawString("Winning!", 100, 100);
g.setColor(Color.BLACK);
g.setFont(restartFont);
g.drawString("Press R to restart", 100, 150);
g.drawString("Press ESC to exit", 100, 180);
} else {
g.setColor(Color.YELLOW);
g.setFont(scoresFont);
g.drawString("Scores: " + player.getScores(), 10, 40);
}
}
}
class GraphicsWindow extends JFrame {
private final Viewport viewport;
public GraphicsWindow(String title, int width, int height) throws IOException {
super(title);
viewport = new Viewport(this);
add(viewport);
pack();
setSize(width, height);
setResizable(false);
setFocusable(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
viewport.initializeGame();
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
event.consume();
viewport.handleKeyPress(event);
}
public void keyReleased(KeyEvent event) {
event.consume();
viewport.handleKeyRelease(event);
}
});
Timer timer = new Timer(33, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
long time = System.currentTimeMillis();
viewport.updateGame(33.0f / 1000.0f);
viewport.repaint();
}
});
timer.start();
}
public Viewport getViewport() {
return viewport;
}
}
public class Main {
public static void main(String[] args) throws IOException {
new GraphicsWindow("Asteroids game", 640, 480);
}
}