From 6a4ef35b9a27b8cc46d8e2aed1422619dd2ba6dc Mon Sep 17 00:00:00 2001 From: barto <18618583+rajlu@users.noreply.github.com> Date: Fri, 24 Apr 2020 18:00:10 +0200 Subject: [PATCH] Big code cleanup --- README.md | 10 +- src/GameStarter.java | 2 + src/components/background/Background.java | 23 +-- src/components/dino/Dino.java | 203 +++++++++----------- src/components/ground/Ground.java | 41 ++-- src/components/obstacles/ObstacleImage.java | 44 +++-- src/components/obstacles/Obstacles.java | 123 ++++++------ src/components/ui/GameOver.java | 4 +- src/components/ui/Intro.java | 14 +- src/components/ui/Paused.java | 18 +- src/components/ui/Score.java | 62 +++--- src/components/utility/Animation.java | 8 +- src/components/utility/Coordinates.java | 4 + src/components/utility/DeltaTime.java | 10 +- src/components/utility/Sound.java | 4 +- src/main/GamePanel.java | 73 +++---- src/main/GameWindow.java | 5 +- 17 files changed, 309 insertions(+), 339 deletions(-) diff --git a/README.md b/README.md index a98fa22..bb78241 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Version](https://img.shields.io/github/v/tag/rajlu/awesome-dino?label=Version&style=for-the-badge) ![Repo size](https://img.shields.io/github/repo-size/rajlu/awesome-dino?style=for-the-badge) ![Code size](https://img.shields.io/github/languages/code-size/rajlu/awesome-dino?style=for-the-badge) A Java version ot the offline T-Rex chrome game. Some features are missing, some additional has been added. -Game works on ~**60 fps**. +Game works on ~**60 FPS**. Game is for my CS project. ## Features @@ -20,9 +20,13 @@ Game is for my CS project. - Intro - Pause - Sounds - - **EASTER EGG** _(u need to click somewhere on intro screen)_ + - **EASTER EGG** _(you need to click somewhere in intro screen)_ -## Keybinds: +## How to start +1. Clone git +2. Run from "GameStarter" class + +## Keybinds ##### Jump: `SPACE`, `w`, `ARROW UP` ##### Fall: `s`, `ARROW DOWN` ##### Pause: `p`, `ESC` diff --git a/src/GameStarter.java b/src/GameStarter.java index d56dae4..a8fe3ea 100644 --- a/src/GameStarter.java +++ b/src/GameStarter.java @@ -4,6 +4,8 @@ public class GameStarter { public static void main(String[] args) { + System.out.println("\nStartup log"); + System.out.println("-----------------------------------------------------"); SwingUtilities.invokeLater(GameWindow::new); } } diff --git a/src/components/background/Background.java b/src/components/background/Background.java index c9fabe0..7340a5b 100644 --- a/src/components/background/Background.java +++ b/src/components/background/Background.java @@ -14,19 +14,18 @@ import static main.GameWindow.WINDOW_WIDTH; public class Background implements Drawable { - private ArrayList cloudImages; - private final BufferedImage cloud; + private static final BufferedImage CLOUD_IMAGE = new Resource().getResourceImage("/assets/Cloud.png"); private final int backgroundSpeed = gameSpeed / 3; private BackgroundColors backgroundColor; - ComponentImage firstCloud; - ComponentImage secondCloud; - ComponentImage thirdCloud; + private static ArrayList cloudImages; + private static final ComponentImage firstCloud = new ComponentImage(CLOUD_IMAGE, WINDOW_WIDTH - 700, 40, Color.LIGHT_GRAY); + private static final ComponentImage secondCloud = new ComponentImage(CLOUD_IMAGE, WINDOW_WIDTH - 400, 20, Color.LIGHT_GRAY); + private static final ComponentImage thirdCloud = new ComponentImage(CLOUD_IMAGE, WINDOW_WIDTH - 200, 80, Color.LIGHT_GRAY); public Background() { - cloud = new Resource().getResourceImage("/assets/Cloud.png"); backgroundColor = BackgroundColors.DEFAULT; backgroundInit(); @@ -38,13 +37,9 @@ public void setBackgroundColor(BackgroundColors backgroundColor) { private void backgroundInit() { cloudImages = new ArrayList<>(); - cloudImages.add(new ComponentImage(cloud, WINDOW_WIDTH - 700, 40, Color.LIGHT_GRAY)); - cloudImages.add(new ComponentImage(cloud, WINDOW_WIDTH - 400, 20, Color.LIGHT_GRAY)); - cloudImages.add(new ComponentImage(cloud, WINDOW_WIDTH - 200, 80, Color.LIGHT_GRAY)); - - firstCloud = cloudImages.get(0); - secondCloud = cloudImages.get(1); - thirdCloud = cloudImages.get(2); + cloudImages.add(firstCloud); + cloudImages.add(secondCloud); + cloudImages.add(thirdCloud); } private void changeBackgroundColor() { @@ -88,7 +83,7 @@ public void draw(Graphics g) { } for (ComponentImage clouds : cloudImages) { - if (DEBUG_MODE) { + if (debugMode) { g.setColor(clouds.debugColor); g.drawRect(clouds.x, clouds.y, clouds.image.getWidth(), clouds.image.getHeight()); } diff --git a/src/components/dino/Dino.java b/src/components/dino/Dino.java index 2399d41..3989e08 100644 --- a/src/components/dino/Dino.java +++ b/src/components/dino/Dino.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import static components.ground.Ground.GROUND_Y; -import static main.GamePanel.DEBUG_MODE; +import static main.GamePanel.debugMode; import static main.GamePanel.GAME_GRAVITY; public class Dino implements Drawable { @@ -16,10 +16,36 @@ public class Dino implements Drawable { private static final int DINO_FALL_STRENGTH = 8; private static final float DINO_START_X = 50; private static int DINO_RUNNING_ANIMATION_DELTA_TIME = 60; + private static final int DINO_BORDER_SIZE = 1; - private static DinoStates dinoState; + private static final float X = DINO_START_X; - private static float x, y; + public static boolean isMario = false; + public static boolean marioLoaded = false; + + private static DinoStates dinoState = DinoStates.IDLE; + + private static BufferedImage idleImage = new Resource().getResourceImage("/assets/Dino-stand.png"); + private static BufferedImage jumpImage = new Resource().getResourceImage("/assets/Dino-stand.png"); + private static Animation runAnimation = new Animation(DINO_RUNNING_ANIMATION_DELTA_TIME); + private static BufferedImage dieImage = new Resource().getResourceImage("/assets/Dino-big-eyes.png"); + + /** + * Collision adjustments. + * It is modified version from chromium source code. + * --------------------------------------------------- + * ______ + * _| |-| + * | | dino | | + * |_| |_| + * |_____ | + */ + public static ArrayList constructedCoordinates = new ArrayList<>(); + private static final Coordinates collisionLeft = new Coordinates(0, 15, 11 - DINO_BORDER_SIZE, 21 - DINO_BORDER_SIZE); + private static final Coordinates collisionMiddle = new Coordinates(10, 0, 22 - DINO_BORDER_SIZE, 45 - DINO_BORDER_SIZE); + private static final Coordinates collisionRight = new Coordinates(31, 0, 10 - DINO_BORDER_SIZE, 21 - DINO_BORDER_SIZE); + + private static float y = GROUND_Y - idleImage.getHeight(); private static float speedY; /** @@ -28,62 +54,80 @@ public class Dino implements Drawable { */ private static float TEMP_y; - private static BufferedImage idleImage; - private static BufferedImage jumpImage; - private static Animation runAnimation; - private static BufferedImage dieImage; - - public static ArrayList constructedCoordinates; - private static Coordinates collisionLeft; - private static Coordinates collisionMiddle; - private static Coordinates collisionRight; - /** * It eliminates system delay between typed key event and pressed key event */ - public static boolean jumpRequested; + public boolean jumpRequested; - private static Sound jumpSound; - public static Sound gameOverSound; + private static Sound jumpSound = new Sound("/assets/sounds/button-press.wav"); + public Sound gameOverSound = new Sound("/assets/sounds/hit.wav"); public Dino() { - idleImage = new Resource().getResourceImage("/assets/Dino-stand.png"); - jumpImage = new Resource().getResourceImage("/assets/Dino-stand.png");; - runAnimation = new Animation(DINO_RUNNING_ANIMATION_DELTA_TIME); runAnimation.addFrame(new Resource().getResourceImage("/assets/Dino-left-up.png")); runAnimation.addFrame(new Resource().getResourceImage("/assets/Dino-right-up.png")); - dieImage = new Resource().getResourceImage("/assets/Dino-big-eyes.png"); - x = DINO_START_X; - y = GROUND_Y - idleImage.getHeight(); - dinoState = DinoStates.IDLE; - - jumpSound = new Sound("/assets/sounds/button-press.wav"); - gameOverSound = new Sound("/assets/sounds/hit.wav"); - - // Collision adjustments. - // It is modified version from chromium source code. - // --------------------------------------------------- - // ______ - // _| |-| - // | | dino | | - // |_| |_| - // |_____ | - int borderSize = 1; - constructedCoordinates = new ArrayList<>(); + constructedCoordinates.add(new Coordinates((int) X, (int) y + collisionLeft.y, collisionLeft.width, collisionLeft.height)); + constructedCoordinates.add(new Coordinates((int) X + collisionMiddle.x, (int) y, collisionMiddle.width, collisionMiddle.height)); + constructedCoordinates.add(new Coordinates((int) X + collisionRight.x, (int) y, collisionRight.width, collisionRight.height)); + } + + public void run() { + dinoState = DinoStates.RUNNING; + } + + public void jump() { + if (dinoState == DinoStates.RUNNING) { + dinoState = DinoStates.JUMPING; + + speedY = -DINO_JUMP_STRENGTH; + y += speedY; + + // It prevents from layering sounds and game freeze + if (!jumpSound.isNull()) { + if (jumpSound.isOpen()) jumpSound.stop(); + } + jumpSound.play(); + } else if (dinoState == DinoStates.JUMPING) { + jumpRequested = true; + } + } + + public void fall() { + if (dinoState == DinoStates.JUMPING) { + speedY = DINO_FALL_STRENGTH; + y += speedY; + } + } + + public void die() { + dinoState = DinoStates.DIE; + gameOverSound.play(); + } + + public void setMario() { + System.out.println("\nMARIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"); + DINO_RUNNING_ANIMATION_DELTA_TIME = 100; + + idleImage = new Resource().getResourceImage("/assets/mario/Mario-welcome.png"); + jumpImage = new Resource().getResourceImage("/assets/mario/Mario-jump.png"); + runAnimation = new Animation(DINO_RUNNING_ANIMATION_DELTA_TIME); + runAnimation.addFrame(new Resource().getResourceImage("/assets/mario/Mario-left-up.png")); + runAnimation.addFrame(new Resource().getResourceImage("/assets/mario/Mario-right-up.png")); + dieImage = new Resource().getResourceImage("/assets/mario/Mario-dead.png"); + + jumpSound = new Sound("/assets/sounds/mario/jump.wav"); + gameOverSound = new Sound("/assets/sounds/mario/dead.wav"); - collisionLeft = new Coordinates(0, 15, 11 - borderSize, 21 - borderSize); - collisionMiddle = new Coordinates(10, 0, 22 - borderSize, 45 - borderSize); - collisionRight = new Coordinates(31, 0, 10 - borderSize, 21 - borderSize); + constructedCoordinates = new ArrayList<>(); + constructedCoordinates.add(new Coordinates((int) X, (int) y, idleImage.getWidth(), idleImage.getHeight())); - constructedCoordinates.add(new Coordinates((int) x, (int) y + collisionLeft.y, collisionLeft.width, collisionLeft.height)); - constructedCoordinates.add(new Coordinates((int) x + collisionMiddle.x, (int) y, collisionMiddle.width, collisionMiddle.height)); - constructedCoordinates.add(new Coordinates((int) x + collisionRight.x, (int) y, collisionRight.width, collisionRight.height)); + marioLoaded = true; + System.out.println("MARIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"); } @Override public void draw(Graphics g) { - if (DEBUG_MODE) { + if (debugMode) { for (Coordinates coordinates : constructedCoordinates) { g.setColor(Color.BLACK); g.drawRect(coordinates.x, coordinates.y, coordinates.width, coordinates.height); @@ -91,24 +135,21 @@ public void draw(Graphics g) { } switch (dinoState) { case IDLE: - g.drawImage(idleImage, (int)x, (int)y, null); + g.drawImage(idleImage, (int) X, (int)y, null); break; case JUMPING: - g.drawImage(jumpImage, (int)x, (int)y, null); + g.drawImage(jumpImage, (int) X, (int)y, null); break; case RUNNING: runAnimation.update(); - g.drawImage(runAnimation.getFrame(), (int)x, (int)y, null); + g.drawImage(runAnimation.getFrame(), (int) X, (int)y, null); break; case DIE: - g.drawImage(dieImage, (int)x, (int)y, null); + g.drawImage(dieImage, (int) X, (int)y, null); break; } } - /** - * - */ @Override public void update() { if((TEMP_y + speedY) >= GROUND_Y - idleImage.getHeight()) { @@ -125,16 +166,16 @@ public void update() { TEMP_y = y; } if (constructedCoordinates.size() > 1) { - constructedCoordinates.get(0).x = (int) x; + constructedCoordinates.get(0).x = (int) X; constructedCoordinates.get(0).y = (int) y + collisionLeft.y; - constructedCoordinates.get(1).x = (int) x + collisionMiddle.x; + constructedCoordinates.get(1).x = (int) X + collisionMiddle.x; constructedCoordinates.get(1).y = (int) y; - constructedCoordinates.get(2).x = (int) x + collisionRight.x; + constructedCoordinates.get(2).x = (int) X + collisionRight.x; constructedCoordinates.get(2).y = (int) y; } else { - constructedCoordinates.get(0).x = (int) x; + constructedCoordinates.get(0).x = (int) X; constructedCoordinates.get(0).y = (int) y; } @@ -145,56 +186,4 @@ public void reset() { y = GROUND_Y - idleImage.getHeight(); run(); } - - public void run() { - dinoState = DinoStates.RUNNING; - } - - public void jump() { - if (dinoState == DinoStates.RUNNING) { - dinoState = DinoStates.JUMPING; - - speedY = -DINO_JUMP_STRENGTH; - y += speedY; - - // It prevents from layering sounds and game freeze - if (!jumpSound.isNull()) { - if (jumpSound.isOpen()) jumpSound.stop(); - } - jumpSound.play(); - } else if (dinoState == DinoStates.JUMPING) { - jumpRequested = true; - } - } - - public void fall() { - if (dinoState == DinoStates.JUMPING) { - speedY = DINO_FALL_STRENGTH; - y += speedY; - } - } - - public void die() { - dinoState = DinoStates.DIE; - gameOverSound.play(); - } - - public static void setMario() { - System.out.println("\nMARIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"); - DINO_RUNNING_ANIMATION_DELTA_TIME = 100; - - idleImage = new Resource().getResourceImage("/assets/mario/Mario-welcome.png"); - jumpImage = new Resource().getResourceImage("/assets/mario/Mario-jump.png"); - runAnimation = new Animation(DINO_RUNNING_ANIMATION_DELTA_TIME); - runAnimation.addFrame(new Resource().getResourceImage("/assets/mario/Mario-left-up.png")); - runAnimation.addFrame(new Resource().getResourceImage("/assets/mario/Mario-right-up.png")); - dieImage = new Resource().getResourceImage("/assets/mario/Mario-dead.png"); - - jumpSound = new Sound("/assets/sounds/mario/jump.wav"); - gameOverSound = new Sound("/assets/sounds/mario/dead.wav"); - - constructedCoordinates = new ArrayList<>(); - constructedCoordinates.add(new Coordinates((int) x, (int) y, idleImage.getWidth(), idleImage.getHeight())); - System.out.println("MARIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"); - } } diff --git a/src/components/ground/Ground.java b/src/components/ground/Ground.java index 2f03776..ff54fab 100644 --- a/src/components/ground/Ground.java +++ b/src/components/ground/Ground.java @@ -3,57 +3,52 @@ import components.utility.ComponentImage; import interfaces.Drawable; import components.utility.Resource; +import main.GamePanel; import java.awt.*; import java.awt.image.BufferedImage; import java.util.ArrayList; -import static main.GamePanel.*; - public class Ground implements Drawable { - public static final int GROUND_Y = 180; private static final int GROUND_Y_IMAGE_OFFSET = -9; + private static final BufferedImage GROUND_IMAGE = new Resource().getResourceImage("/assets/Ground.png"); + public static final int GROUND_Y = 180; - private ArrayList groundImages; - private BufferedImage image; + private static ArrayList groundImages; - ComponentImage first; - ComponentImage second; + private static final ComponentImage firstGround = new ComponentImage(GROUND_IMAGE, 0, Color.green); + private static final ComponentImage secondGround = new ComponentImage(GROUND_IMAGE, GROUND_IMAGE.getWidth(), Color.blue); public Ground() { - image = new Resource().getResourceImage("/assets/Ground.png"); - groundInit(); } - public void groundInit() { + private void groundInit() { groundImages = new ArrayList<>(); - groundImages.add(new ComponentImage(image, 0, Color.green)); - groundImages.add(new ComponentImage(image, groundImages.get(0).image.getWidth(), Color.blue)); - first = groundImages.get(0); - second = groundImages.get(1); + groundImages.add(firstGround); + groundImages.add(secondGround); } /** - * @see ComponentImage#x Defines also inequalities arising - * from updating x before changing GroundImage possition (I think) + * @see ComponentImage#x Defines also inequalities arising + * from updating x before changing GroundImage possition (I think) */ public void update() { - first.x -= gameSpeed; - second.x -= gameSpeed; + firstGround.x -= GamePanel.gameSpeed; + secondGround.x -= GamePanel.gameSpeed; - if (first.x <= -first.image.getWidth()) { - first.x = second.image.getWidth() + second.x; + if (firstGround.x <= -firstGround.image.getWidth()) { + firstGround.x = secondGround.image.getWidth() + secondGround.x; } - if (second.x <= -second.image.getWidth()) { - second.x = first.image.getWidth() + first.x; + if (secondGround.x <= -secondGround.image.getWidth()) { + secondGround.x = firstGround.image.getWidth() + firstGround.x; } } public void draw(Graphics g) { for (ComponentImage ground : groundImages) { - if (DEBUG_MODE) { + if (GamePanel.debugMode) { g.setColor(ground.debugColor); g.drawLine(ground.x, GROUND_Y, ground.image.getWidth() + ground.x, GROUND_Y); } diff --git a/src/components/obstacles/ObstacleImage.java b/src/components/obstacles/ObstacleImage.java index 43b72b4..a1bc79e 100644 --- a/src/components/obstacles/ObstacleImage.java +++ b/src/components/obstacles/ObstacleImage.java @@ -9,42 +9,60 @@ import static components.ground.Ground.GROUND_Y; public class ObstacleImage { + private final ComponentImage OBSTACLE_IMAGE; private int spaceBehind; public Coordinates coordinates; - private ComponentImage image; + public ObstacleImage(BufferedImage OBSTACLE_IMAGE) { + this.OBSTACLE_IMAGE = new ComponentImage(OBSTACLE_IMAGE, 0, GROUND_Y - OBSTACLE_IMAGE.getHeight(), Color.red); + this.spaceBehind = 0; - public ObstacleImage(BufferedImage image, int x) { - this.image = new ComponentImage(image, x, GROUND_Y - image.getHeight(), Color.red); + coordinates = new Coordinates(this.OBSTACLE_IMAGE.x, this.OBSTACLE_IMAGE.y, OBSTACLE_IMAGE.getWidth(), OBSTACLE_IMAGE.getHeight()); + } + + public ObstacleImage(BufferedImage OBSTACLE_IMAGE, int spaceBehind) { + this.OBSTACLE_IMAGE = new ComponentImage(OBSTACLE_IMAGE, 0, GROUND_Y - OBSTACLE_IMAGE.getHeight(), Color.red); + this.spaceBehind = spaceBehind; - coordinates = new Coordinates(this.image.x, this.image.y, image.getWidth(), image.getHeight()); + coordinates = new Coordinates(this.OBSTACLE_IMAGE.x, this.OBSTACLE_IMAGE.y, OBSTACLE_IMAGE.getWidth(), OBSTACLE_IMAGE.getHeight()); } - public void setSpaceBehind(int spaceBehind) { + public ObstacleImage(BufferedImage OBSTACLE_IMAGE, int x, int spaceBehind) { + this.OBSTACLE_IMAGE = new ComponentImage(OBSTACLE_IMAGE, x, GROUND_Y - OBSTACLE_IMAGE.getHeight(), Color.red); this.spaceBehind = spaceBehind; + + coordinates = new Coordinates(this.OBSTACLE_IMAGE.x, this.OBSTACLE_IMAGE.y, OBSTACLE_IMAGE.getWidth(), OBSTACLE_IMAGE.getHeight()); } - public int getSpaceBehind() { - return spaceBehind; + // Setters --------------------------------------------------------------- + public void setSpaceBehind(int spaceBehind) { + this.spaceBehind = spaceBehind; } public void setX(int x) { - this.image.x = x; + this.OBSTACLE_IMAGE.x = x; coordinates.x = x; } + // Getters --------------------------------------------------------------- public int getX() { - return image.x; + return OBSTACLE_IMAGE.x; } + public int getY() { - return image.y; + return OBSTACLE_IMAGE.y; } + public Color getDebugColor() { - return image.debugColor; + return OBSTACLE_IMAGE.debugColor; } - public BufferedImage getImage() { - return image.image; + public BufferedImage getOBSTACLE_IMAGE() { + return OBSTACLE_IMAGE.image; + } + + public int getSpaceBehind() { + return spaceBehind; } } diff --git a/src/components/obstacles/Obstacles.java b/src/components/obstacles/Obstacles.java index c0ac9e1..28b20cc 100644 --- a/src/components/obstacles/Obstacles.java +++ b/src/components/obstacles/Obstacles.java @@ -4,116 +4,109 @@ import components.utility.Coordinates; import interfaces.Drawable; import components.utility.Resource; +import main.GamePanel; import java.awt.*; import java.util.ArrayList; -import static main.GamePanel.*; - public class Obstacles implements Drawable { - public static final int OBSTACLES_MIN_SPACE_BETWEEN = 250; - public static final int OBSTACLES_MAX_SPACE_BETWEEN = 500; - public static final int OBSTACLES_FIRST_OBSTACLE_X = 600; + private static final int OBSTACLES_MIN_SPACE_BETWEEN = 250; + private static final int OBSTACLES_MAX_SPACE_BETWEEN = 500; + private static final int OBSTACLES_FIRST_OBSTACLE_X = 600; + private static final int RANGE_SPACE_BETWEEN_OBSTACLES = OBSTACLES_MAX_SPACE_BETWEEN - OBSTACLES_MIN_SPACE_BETWEEN + 1; - private final ArrayList obstacleImages; - private final int rangeSpaceBetweenObstacles; + private static final ArrayList OBSTACLE_IMAGES = new ArrayList<>(); - private final int maxIncomingObstacles; + private static final int MAX_INCOMING_OBSTACLES = 5; private ArrayList incomingObstacles; public Obstacles() { - obstacleImages = new ArrayList<>(); - - // TODO: rewrite to support more obstacles which depend on window width - maxIncomingObstacles = 5; - - ObstacleImage cactus1 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-1.png"), 0); - ObstacleImage cactus2 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-2.png"), 0); - ObstacleImage cactusTriple = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-3.png"), 0); - ObstacleImage cactusDouble1 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-4.png"), 0); - ObstacleImage cactusDouble2 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-5.png"), 0); - - rangeSpaceBetweenObstacles = OBSTACLES_MAX_SPACE_BETWEEN - OBSTACLES_MIN_SPACE_BETWEEN + 1; - - obstacleImages.add(cactus1); - obstacleImages.add(cactus2); - obstacleImages.add(cactusTriple); - obstacleImages.add(cactusDouble1); - obstacleImages.add(cactusDouble2); + ObstacleImage cactus1 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-1.png")); + ObstacleImage cactus2 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-2.png")); + ObstacleImage cactusTriple = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-3.png")); + ObstacleImage cactusDouble1 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-4.png")); + ObstacleImage cactusDouble2 = new ObstacleImage(new Resource().getResourceImage("/assets/Cactus-5.png")); + + OBSTACLE_IMAGES.add(cactus1); + OBSTACLE_IMAGES.add(cactus2); + OBSTACLE_IMAGES.add(cactusTriple); + OBSTACLE_IMAGES.add(cactusDouble1); + OBSTACLE_IMAGES.add(cactusDouble2); initFirstObstacles(); } - public ObstacleImage getRandomObstacle() { - int randCactus = (int) (Math.random() * (obstacleImages.size())); - ObstacleImage randObstacle = obstacleImages.get(randCactus); - return new ObstacleImage(randObstacle.getImage(), randObstacle.getX()); - } - - public ObstacleImage getRandomObstacle(int x) { - int randCactus = (int) (Math.random() * (obstacleImages.size())); - ObstacleImage randObstacle = obstacleImages.get(randCactus); - return new ObstacleImage(randObstacle.getImage(), x); - } - - public int getRandomSpace() { - return (int) (Math.random() * rangeSpaceBetweenObstacles) + OBSTACLES_MIN_SPACE_BETWEEN; - } - - public void initFirstObstacles() { + private void initFirstObstacles() { incomingObstacles = new ArrayList<>(); - for (int i = 0; i < maxIncomingObstacles; i++) { + for (int i = 0; i < MAX_INCOMING_OBSTACLES; i++) { ObstacleImage rand = getRandomObstacle(); incomingObstacles.add(rand); if (i == 0) { incomingObstacles.get(0).setX(OBSTACLES_FIRST_OBSTACLE_X); - incomingObstacles.get(0).setSpaceBehind(getRandomSpace()); } else { incomingObstacles.get(i).setX(incomingObstacles.get(i - 1).getX() + incomingObstacles.get(i - 1).getSpaceBehind()); - incomingObstacles.get(i).setSpaceBehind(getRandomSpace()); } } } - public void reset() { - initFirstObstacles(); + private ObstacleImage getRandomObstacle() { + int randCactus = (int) (Math.random() * (OBSTACLE_IMAGES.size())); + ObstacleImage randObstacle = OBSTACLE_IMAGES.get(randCactus); + + return new ObstacleImage(randObstacle.getOBSTACLE_IMAGE(), getRandomSpace()); } - public void update() { - for (ObstacleImage obstacle : incomingObstacles) { - obstacle.setX(obstacle.getX() - gameSpeed); - } + private ObstacleImage getRandomObstacle(int x) { + int randCactus = (int) (Math.random() * (OBSTACLE_IMAGES.size())); + ObstacleImage randObstacle = OBSTACLE_IMAGES.get(randCactus); - if (incomingObstacles.get(0).getX() < -incomingObstacles.get(0).getImage().getWidth()) { - incomingObstacles.remove(0); - incomingObstacles.add(getRandomObstacle( - incomingObstacles.get(incomingObstacles.size() - 1).getX() + incomingObstacles.get(incomingObstacles.size() - 1).getSpaceBehind() - )); - incomingObstacles.get(incomingObstacles.size() - 1).setSpaceBehind(getRandomSpace()); - } + return new ObstacleImage(randObstacle.getOBSTACLE_IMAGE(), x, getRandomSpace()); + } - isCollision(); + private int getRandomSpace() { + return (int) (Math.random() * RANGE_SPACE_BETWEEN_OBSTACLES) + OBSTACLES_MIN_SPACE_BETWEEN; } public boolean isCollision() { for (ObstacleImage obstacle : incomingObstacles) { for (Coordinates dinoCoordinates : Dino.constructedCoordinates) - if (dinoCoordinates.intersects(obstacle.coordinates)) { - return true; - } + if (dinoCoordinates.intersects(obstacle.coordinates)) { + return true; + } } return false; } + @Override + public void reset() { + initFirstObstacles(); + } + + @Override + public void update() { + for (ObstacleImage obstacle : incomingObstacles) { + obstacle.setX(obstacle.getX() - GamePanel.gameSpeed); + } + + if (incomingObstacles.get(0).getX() < -incomingObstacles.get(0).getOBSTACLE_IMAGE().getWidth()) { + ObstacleImage lastIncomingObstacle = incomingObstacles.get(incomingObstacles.size() - 1); + + incomingObstacles.remove(0); + incomingObstacles.add(getRandomObstacle(lastIncomingObstacle.getX() + lastIncomingObstacle.getSpaceBehind())); + incomingObstacles.get(incomingObstacles.size() - 1).setSpaceBehind(getRandomSpace()); + } + } + + @Override public void draw(Graphics g) { for (ObstacleImage obstacle : incomingObstacles) { - if (DEBUG_MODE) { + if (GamePanel.debugMode) { g.setColor(obstacle.getDebugColor()); g.drawRect(obstacle.coordinates.x, obstacle.coordinates.y, obstacle.coordinates.width, obstacle.coordinates.height); } - g.drawImage(obstacle.getImage(), obstacle.getX(), obstacle.getY(), null); + g.drawImage(obstacle.getOBSTACLE_IMAGE(), obstacle.getX(), obstacle.getY(), null); } } } diff --git a/src/components/ui/GameOver.java b/src/components/ui/GameOver.java index 95a0577..4f6771b 100644 --- a/src/components/ui/GameOver.java +++ b/src/components/ui/GameOver.java @@ -10,8 +10,8 @@ import static main.GameWindow.WINDOW_WIDTH; public class GameOver implements Drawable { - private final BufferedImage text = new Resource().getResourceImage("/assets/Game-over.png"); - private final BufferedImage restartButton = new Resource().getResourceImage("/assets/Restart.png"); + private static final BufferedImage text = new Resource().getResourceImage("/assets/Game-over.png"); + private static final BufferedImage restartButton = new Resource().getResourceImage("/assets/Restart.png"); public GameOver() { } diff --git a/src/components/ui/Intro.java b/src/components/ui/Intro.java index 4abe0fd..6d76022 100644 --- a/src/components/ui/Intro.java +++ b/src/components/ui/Intro.java @@ -15,28 +15,26 @@ import static main.GameWindow.WINDOW_WIDTH; public class Intro implements Drawable { - public boolean IS_MARIO = false; + private static BufferedImage text = new Resource().getResourceImage("/assets/Intro.png"); - private BufferedImage text = new Resource().getResourceImage("/assets/Intro.png"); - public JLabel label = new JLabel(); + public JLabel introLabel = new JLabel(); public final Sound overworld = new Sound("/assets/sounds/mario/overworld.wav"); public Intro() { - label.setBounds((WINDOW_WIDTH - text.getWidth()) / 2, (WINDOW_HEIGHT - text.getHeight()) / 2 - 50, text.getWidth(), text.getHeight()); - label.addMouseListener(new MouseAdapter() { + introLabel.setBounds((WINDOW_WIDTH - text.getWidth()) / 2, (WINDOW_HEIGHT - text.getHeight()) / 2 - 50, text.getWidth(), text.getHeight()); + introLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - IS_MARIO = true; changeIntroTextToMario(); overworld.playInLoop(); - Dino.setMario(); + Dino.isMario = true; } }); } public void setVisible(boolean val) { - label.setVisible(val); + introLabel.setVisible(val); } public void changeIntroTextToMario() {text = new Resource().getResourceImage("/assets/Intro-mario.png");} diff --git a/src/components/ui/Paused.java b/src/components/ui/Paused.java index 76a0a40..655bc11 100644 --- a/src/components/ui/Paused.java +++ b/src/components/ui/Paused.java @@ -10,25 +10,19 @@ import static main.GameWindow.WINDOW_WIDTH; public class Paused implements Drawable { - private final BufferedImage text = new Resource().getResourceImage("/assets/Paused.png"); + private static final BufferedImage PAUSED_TEXT = new Resource().getResourceImage("/assets/Paused.png"); - public Paused() { - - } - - @Override - public void update() { - - } + public Paused() { } @Override public void draw(Graphics g) { System.out.println("draw pause"); - g.drawImage(text, (WINDOW_WIDTH - text.getWidth())/ 2, (WINDOW_HEIGHT - text.getHeight()) / 2 - 70, null); + g.drawImage(PAUSED_TEXT, (WINDOW_WIDTH - PAUSED_TEXT.getWidth())/ 2, (WINDOW_HEIGHT - PAUSED_TEXT.getHeight()) / 2 - 70, null); } @Override - public void reset() { + public void update() { } - } + @Override + public void reset() { } } diff --git a/src/components/ui/Score.java b/src/components/ui/Score.java index 5876dcd..c6dd5ae 100644 --- a/src/components/ui/Score.java +++ b/src/components/ui/Score.java @@ -17,21 +17,15 @@ public class Score implements Drawable { private static final int SCORE_DELTA_TIME = 100 / gameSpeed * 5; private static final int SCORE_MAX_HIGH_SCORE = 99999; - public static int score; - private int highScore; + private static final DeltaTime DELTA_TIME = new DeltaTime(SCORE_DELTA_TIME); + private static final Sound SCORE_SOUND = new Sound("/assets/sounds/score-reached.wav"); - private final DeltaTime deltaTime; + private static boolean isPlayed = false; - private final Sound scoreSound; - private boolean isPlayed = false; + private static int highScore = readHighScore(); + public static int score = 0; - public Score() { - score = 0; - deltaTime = new DeltaTime(SCORE_DELTA_TIME); - scoreSound = new Sound("/assets/sounds/score-reached.wav"); - - highScore = readHighScore(); - } + public Score() { } private String scoreBuilder(int score) { StringBuilder ret = new StringBuilder(Integer.toString(score)); @@ -47,7 +41,7 @@ private String scoreBuilder(int score) { private void playSound() { if (score > 0 && score%100 == 0 && !isPlayed) { isPlayed = true; - scoreSound.play(); + SCORE_SOUND.play(); } } @@ -58,6 +52,26 @@ private String printScore(int score) { return score > SCORE_MAX_HIGH_SCORE ? Integer.toString(SCORE_MAX_HIGH_SCORE) : scoreBuilder(score); } + private static boolean checkFileExistence() { + File file = new File(SCORE_FILE_NAME); + return file.exists(); + } + + private static int readHighScore() { + long highScore = 0; + if (checkFileExistence()) { + try { + BufferedReader reader = new BufferedReader(new FileReader(SCORE_FILE_NAME)); + highScore = Long.parseLong(reader.readLine()); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + System.out.println("Score system: High score read"); + return (int) highScore; + } + /** * https://stackoverflow.com/questions/12350248/java-difference-between-filewriter-and-bufferedwriter * ------------------------------------------------------------------------------------------------------- @@ -84,29 +98,9 @@ public void writeHighScore() { } } - public boolean checkFileExistence() { - File file = new File(SCORE_FILE_NAME); - return file.exists(); - } - - public int readHighScore() { - long highScore = 0; - if (checkFileExistence()) { - try { - BufferedReader reader = new BufferedReader(new FileReader(SCORE_FILE_NAME)); - highScore = Long.parseLong(reader.readLine()); - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("Score system: High score read"); - return (int) highScore; - } - @Override public void update() { - if (deltaTime.canExecute()) { + if (DELTA_TIME.canExecute()) { isPlayed = false; GamePanel.isGameSpeedChanged = false; score += 1; diff --git a/src/components/utility/Animation.java b/src/components/utility/Animation.java index 462c4de..59d37c8 100644 --- a/src/components/utility/Animation.java +++ b/src/components/utility/Animation.java @@ -10,20 +10,20 @@ */ public class Animation { + private final DeltaTime DELTA_TIME; + private ArrayList frames; private int index; - private DeltaTime deltaTime; - public Animation(int deltaTime) { frames = new ArrayList<>(); index = 0; - this.deltaTime = new DeltaTime(deltaTime); + this.DELTA_TIME = new DeltaTime(deltaTime); } public void update() { - if (deltaTime.canExecute()){ + if (DELTA_TIME.canExecute()){ index++; if (index >= frames.size()) { index = 0; diff --git a/src/components/utility/Coordinates.java b/src/components/utility/Coordinates.java index 9dcea36..c434dc7 100644 --- a/src/components/utility/Coordinates.java +++ b/src/components/utility/Coordinates.java @@ -2,6 +2,10 @@ import java.awt.*; +/** + * It is only for cosmetic + * and code clarification purpose + */ public class Coordinates extends Rectangle{ public Coordinates(int x, int y, int width, int height) { this.x = x; diff --git a/src/components/utility/DeltaTime.java b/src/components/utility/DeltaTime.java index d8e473f..e80c517 100644 --- a/src/components/utility/DeltaTime.java +++ b/src/components/utility/DeltaTime.java @@ -1,22 +1,18 @@ package components.utility; public class DeltaTime { - private int deltaTime; + private final int DELTA_TIME; private long lastTime; public DeltaTime(int deltaTime) { - this.deltaTime = deltaTime; + this.DELTA_TIME = deltaTime; } public boolean canExecute() { - if (System.currentTimeMillis() - lastTime > deltaTime) { + if (System.currentTimeMillis() - lastTime > DELTA_TIME) { lastTime = System.currentTimeMillis(); return true; } return false; } - - public void setDeltaTime(int deltaTime) { - this.deltaTime = deltaTime; - } } diff --git a/src/components/utility/Sound.java b/src/components/utility/Sound.java index 258c0c6..21ead5f 100644 --- a/src/components/utility/Sound.java +++ b/src/components/utility/Sound.java @@ -47,9 +47,11 @@ public void playInLoop() { } /** + * It needs to be done before playing song + * * It is important to remove line listener here, because * LineListener will try to execute code which can freeze the game - * if someone will click fast buttons in longer sounds + * if someone will rapid click buttons in longer sounds */ public void stop() { clip.removeLineListener(event); diff --git a/src/main/GamePanel.java b/src/main/GamePanel.java index 0f82290..a6c438e 100644 --- a/src/main/GamePanel.java +++ b/src/main/GamePanel.java @@ -18,17 +18,17 @@ import static main.GameWindow.WINDOW_WIDTH; public class GamePanel extends JPanel implements Runnable, KeyListener { - public static boolean DEBUG_MODE = false; + private static final int GAME_START_SPEED = 5; + private static final int GAME_FPS = 60; + private static final int GAME_MAX_SPEED = 12; - public static final int GAME_FPS = 60; public static final float GAME_GRAVITY = 0.64f; - private static final int GAME_START_SPEED = 5; - public static int GAME_MAX_SPEED = 12; - public static int gameSpeed; - public static boolean isGameSpeedChanged = false; + private Thread mainThread = new Thread(this); - private Thread mainThread; + public static boolean debugMode = false; + public static int gameSpeed = GAME_START_SPEED; + public static boolean isGameSpeedChanged = false; public boolean running = false; public boolean paused = false; @@ -36,40 +36,24 @@ public class GamePanel extends JPanel implements Runnable, KeyListener { public boolean intro = true; final Object pauseLock = new Object(); - Dino dino; - Ground ground; - Obstacles obstacles; - Background background; + Dino dino = new Dino(); + Ground ground = new Ground(); + Obstacles obstacles = new Obstacles(); + Background background = new Background(); - Score scoreUI; - GameOver gameOverUI; - Paused pausedUI; - Intro introUI; + Score scoreUI = new Score(); + GameOver gameOverUI = new GameOver(); + Paused pausedUI = new Paused(); + Intro introUI = new Intro(); public GamePanel() { - System.out.println("\nStartup log"); - System.out.println("-----------------------------------------------------"); - setSize(WINDOW_WIDTH, WINDOW_HEIGHT); - - gameSpeed = GAME_START_SPEED; - - dino = new Dino(); - ground = new Ground(); - obstacles = new Obstacles(); - background = new Background(); - - scoreUI = new Score(); - gameOverUI = new GameOver(); - pausedUI = new Paused(); - introUI = new Intro(); - setLayout(null); - add(introUI.label); + setVisible(true); + + add(introUI.introLabel); - mainThread = new Thread(this); //TODO why "this" mainThread.start(); - setVisible(true); } public void startGame() { @@ -94,14 +78,14 @@ public void resetGame() { ground.reset(); background.reset(); - if (introUI.IS_MARIO) { + if (Dino.isMario) { introUI.overworld.playInLoop(); // It prevents from layering sounds if (dino.gameOverSound.isOpen()) dino.gameOverSound.stop(); } - mainThread = new Thread(this); //TODO why "this" + mainThread = new Thread(this); mainThread.start(); } @@ -119,7 +103,7 @@ public void resumeGame() { } private void changeGameSpeed() { - if (scoreUI.score > 0 && scoreUI.score%260 == 0 && !isGameSpeedChanged && gameSpeed < GAME_MAX_SPEED) { + if (Score.score > 0 && Score.score %260 == 0 && !isGameSpeedChanged && gameSpeed < GAME_MAX_SPEED) { isGameSpeedChanged = true; gameSpeed += 1; } @@ -149,10 +133,7 @@ public void paint(Graphics g) { /** * MAIN GAME LOOP - * - * I'm aware that Thread.sleep() is not a good practice but it is - * good enough for this game. - * + * It is probably the simplest version * ------------------------------------------------------------------------ * Good resources: * - https://gamedev.stackexchange.com/questions/160329/java-game-loop-efficiency @@ -169,6 +150,10 @@ public void run() { e.printStackTrace(); } + if (Dino.isMario && !Dino.marioLoaded) { + dino.setMario(); + } + repaint(); } @@ -200,7 +185,7 @@ public void run() { if (obstacles.isCollision()) { dino.die(); - if (introUI.IS_MARIO) introUI.overworld.stop(); + if (Dino.isMario) introUI.overworld.stop(); scoreUI.writeHighScore(); gameOver = true; running = false; @@ -227,7 +212,7 @@ public void run() { public void keyPressed(KeyEvent e) { // DEBUG if (e.getKeyChar() == '`') { - DEBUG_MODE = !DEBUG_MODE; + debugMode = !debugMode; } // JUMP @@ -273,7 +258,7 @@ public void keyPressed(KeyEvent e) { @Override public void keyReleased(KeyEvent e) { if (e.getKeyChar() == ' ' || e.getKeyChar() == 'w' || e.getKeyCode() == KeyEvent.VK_UP) - Dino.jumpRequested = false; + dino.jumpRequested = false; } @Override diff --git a/src/main/GameWindow.java b/src/main/GameWindow.java index a856c9c..649d44b 100644 --- a/src/main/GameWindow.java +++ b/src/main/GameWindow.java @@ -4,11 +4,12 @@ public class GameWindow { private static final String WINDOW_TITLE = "AWESOME DINO"; - public static final int WINDOW_WIDTH = 800; - public static final int WINDOW_HEIGHT = 240; private static final boolean WINDOW_RESIZABLE = false; private static final boolean WINDOW_ALWAYS_ON_TOP = false; + public static final int WINDOW_WIDTH = 800; + public static final int WINDOW_HEIGHT = 240; + public GameWindow() { JFrame mainGameWindow = new JFrame(WINDOW_TITLE); mainGameWindow.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);