Continue refactoring

This commit is contained in:
Jan-Niclas Loosen 2024-11-28 12:46:32 +01:00
parent 4df15dc254
commit 7af9624252
11 changed files with 82 additions and 115 deletions

View File

@ -8,7 +8,7 @@
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -1,18 +1,20 @@
package com.example.flappybird; /** /**
* Audio.java * Audio.java
* Plays all sound effects * Plays all sound effects
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip; import javax.sound.sampled.Clip;
import java.net.URL; import java.net.URL;
public class Audio { public class Audio {
private void playSound (String sound) {
private void playSound (String sound) {
// Path to sound file // Path to sound file
String soundPath = "/res/sound/" + sound + ".wav"; String soundPath = "/res/sound/" + sound + ".wav";

View File

@ -1,12 +1,13 @@
package com.example.flappybird; /** /**
* Bird.java * Bird.java
* Handles bird's state and actions * Handles bird's state and actions
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
import com.example.flappybird.states.GameState; package com.example.flappybird;
import com.example.flappybird.states.GameState;
import java.awt.*; import java.awt.*;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -15,26 +16,21 @@ public class Bird extends HasPosition {
// Bird attributes // Bird attributes
public String color; public String color;
private boolean isAlive = true; private boolean isAlive = true;
// Bird constants // Bird constants
private int FLOAT_MULTIPLIER = -1; private int FLOAT_MULTIPLIER = -1;
public final int BIRD_WIDTH = 44; public final int BIRD_WIDTH = 44;
public final int BIRD_HEIGHT = 31; public final int BIRD_HEIGHT = 31;
private final int BASE_COLLISION = 521 - BIRD_HEIGHT - 5; private final int BASE_COLLISION = 521 - BIRD_HEIGHT - 5;
private final int SHIFT = 10;
private final int STARTING_BIRD_X = 90;
private final int STARTING_BIRD_Y = 343;
// Physics variables // Physics variables
private double velocity = 0; private double velocity = 0;
private double gravity = .41; private final double gravity = .41;
private double delay = 0; private double delay = 0;
private double rotation = 0;
// Bird sprites // Bird sprites
private BufferedImage[] sprites; private final BufferedImage[] sprites;
private static double currentFrame = 0; private static double currentFrame = 0;
@ -46,30 +42,16 @@ public class Bird extends HasPosition {
} }
/** /**
* @return Bird's x-coordinate * @return If bird is alive
*/ */
public int getX () { public boolean isAlive() {
return x;
}
/**
* @return Bird's y-coordinate
*/
public int getY () {
return y;
}
/**
* @return If bird is alive
*/
public boolean isAlive () {
return isAlive; return isAlive;
} }
/** /**
* Kills bird * Kills bird
*/ */
public void kill () { public void killBird() {
isAlive = false; isAlive = false;
} }
@ -77,15 +59,14 @@ public class Bird extends HasPosition {
* Set new coordinates when starting game * Set new coordinates when starting game
*/ */
public void setGameStartPos () { public void setGameStartPos () {
x = STARTING_BIRD_X; x = 90;
y = STARTING_BIRD_Y; y = 343;
} }
/** /**
* Floating bird effect on menu screen * Floating bird effect on menu screen
*/ */
public void menuFloat () { public void menuFloat () {
y += FLOAT_MULTIPLIER; y += FLOAT_MULTIPLIER;
// Change direction within floating range // Change direction within floating range
@ -101,22 +82,19 @@ public class Bird extends HasPosition {
* Bird jump * Bird jump
*/ */
public void jump () { public void jump () {
if (delay < 1) { if (delay < 1) {
velocity = -SHIFT; int SHIFT = 10;
velocity = -SHIFT;
delay = SHIFT; delay = SHIFT;
} }
} }
/** /**
* Bird movement during the game * Bird movement during the game
*/ */
public void inGame () { public void inGameBorders () {
// If the bird did not hit the base, lower it // If the bird did not hit the base, lower it
if (y < BASE_COLLISION) { if (y < BASE_COLLISION) {
// Change and velocity // Change and velocity
velocity += gravity; velocity += gravity;
@ -125,9 +103,7 @@ public class Bird extends HasPosition {
// Add rounded velocity to y-coordinate // Add rounded velocity to y-coordinate
y += (int) velocity; y += (int) velocity;
} else { } else {
// Play audio and set state to dead // Play audio and set state to dead
GameState.audio.hit(); GameState.audio.hit();
isAlive = false; isAlive = false;
@ -139,9 +115,8 @@ public class Bird extends HasPosition {
* Renders bird * Renders bird
*/ */
public void renderBird (Graphics g) { public void renderBird (Graphics g) {
// Calculate angle to rotate bird based on y-velocity // Calculate angle to rotate bird based on y-velocity
rotation = ((90 * (velocity + 25) / 25) - 90) * Math.PI / 180; double rotation = ((90 * (velocity + 25) / 25) - 90) * Math.PI / 180;
// Divide for clean jump // Divide for clean jump
rotation /= 2; rotation /= 2;

View File

@ -1,10 +1,12 @@
package com.example.flappybird; /** /**
* FlappyBird.java * FlappyBird.java
* Main game class * Main game class
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import javax.swing.*; import javax.swing.*;
import java.awt.event.*; import java.awt.event.*;
import java.awt.Toolkit; import java.awt.Toolkit;
@ -20,7 +22,6 @@ public class FlappyBird extends JFrame implements ActionListener {
private static final int DELAY = 12; private static final int DELAY = 12;
public FlappyBird () { public FlappyBird () {
super("Flappy Bird"); super("Flappy Bird");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT); setSize(WIDTH, HEIGHT);
@ -46,9 +47,8 @@ public class FlappyBird extends JFrame implements ActionListener {
} }
} }
public static void main(String[] args) { public static void main(String[] args) {
FlappyBird game = new FlappyBird(); new FlappyBird();
} }
} }

View File

@ -1,32 +1,24 @@
package com.example.flappybird; /** /**
* GamePanel.java * GamePanel.java
* Main game panel * Main game panel
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import com.example.flappybird.states.GameState; import com.example.flappybird.states.GameState;
import com.example.flappybird.states.MenuState; import com.example.flappybird.states.MenuState;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import javax.swing.*; import javax.swing.*;
import java.net.URI;
import java.util.Random;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.awt.image.BufferedImage;
import java.util.Calendar;
public class GamePanel extends JPanel implements KeyListener, MouseListener { public class GamePanel extends JPanel implements KeyListener, MouseListener {
// Textures // Textures
private GameState gameState; private GameState gameState;
public boolean ready = false; // If game has loaded // If game has loaded
public boolean ready = false;
public GamePanel () { public GamePanel () {
setGameState(new MenuState(this)); setGameState(new MenuState(this));
@ -42,6 +34,10 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
addMouseListener(this); addMouseListener(this);
} }
/**
* Sets the current game state.
* @param state New GameState
*/
public void setGameState(GameState state) { public void setGameState(GameState state) {
System.out.println("Switching to state: " + state.getClass().getName()); System.out.println("Switching to state: " + state.getClass().getName());
this.gameState = state; this.gameState = state;

View File

@ -1,30 +1,30 @@
package com.example.flappybird; /** /**
* Highscore.java * Highscore.java
* Handles setting and getting highscores * Handles setting and getting highscores
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Scanner; import java.util.Scanner;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
public class Highscore { public class Highscore {
// Read / Write to file setup // Read / Write to file setup
private static final String FILE_PATH = "/res/data/highscore.dat"; private static final String FILE_PATH = "/res/data/highscore.dat";
private static final URL dataURL = Highscore.class.getResource(FILE_PATH); private static final URL dataURL = Highscore.class.getResource(FILE_PATH);
private static final File dataFile; private static final File dataFile;
// Highscore
private int bestScore;
static { static {
try { try {
assert dataURL != null; assert dataURL != null;
@ -34,10 +34,7 @@ public class Highscore {
} }
} }
private static Scanner dataScanner = null; private static Scanner dataScanner = null;
// Highscore
private int bestScore;
public Highscore () { public Highscore () {
@ -54,7 +51,7 @@ public class Highscore {
} }
/** /**
* @return Player's highscore * @return Player's highscore
*/ */
public int bestScore () { public int bestScore () {
return bestScore; return bestScore;
@ -62,20 +59,18 @@ public class Highscore {
/** /**
* Sets new highscore in the data file * Sets new highscore in the data file
* * @param newBest New score update
* @param newBest New score update
*/ */
public void setNewBest (int newBest) { public void setNewBest (int newBest) {
// Set new best score // Set new best score
bestScore = newBest; bestScore = newBest;
try { try {
// Write new highscore to data file // Write new highscore to data file
PrintWriter dataWriter = new PrintWriter(FILE_PATH, "UTF-8"); PrintWriter dataWriter = new PrintWriter(FILE_PATH, StandardCharsets.UTF_8);
dataWriter.println(Integer.toString(newBest)); dataWriter.println(newBest);
dataWriter.close(); dataWriter.close();
} catch (FileNotFoundException | UnsupportedEncodingException e) { } catch (IOException e) {
System.out.println("Could not set new highscore!"); System.out.println("Could not set new highscore!");
} }

View File

@ -1,5 +1,3 @@
package com.example.flappybird;
/** /**
* Pipe.java * Pipe.java
* Handles collisions and rendering for pipes * Handles collisions and rendering for pipes
@ -7,6 +5,8 @@ package com.example.flappybird;
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
public class Pipe extends HasPosition { public class Pipe extends HasPosition {
// Placement (top or bottom) of pipe // Placement (top or bottom) of pipe
String location; String location;
@ -31,7 +31,7 @@ public class Pipe extends HasPosition {
super.x = FlappyBird.WIDTH + 5; // Reset x-coordinate super.x = FlappyBird.WIDTH + 5; // Reset x-coordinate
// Set boundaries for top pipes // Set boundaries for top pipes
// This y-coordinte + PIPE_SPACING will be for the bottom pipe // This y-coordinate + PIPE_SPACING will be for the bottom pipe
if (location.equals("top")) { if (location.equals("top")) {
super.y = - Math.max((int) (Math.random() * 320) + 30, 140); super.y = - Math.max((int) (Math.random() * 320) + 30, 140);
} }
@ -46,9 +46,8 @@ public class Pipe extends HasPosition {
/** /**
* Checks for bird colliding with pipe * Checks for bird colliding with pipe
* * @param bird The bird.
* @param bird The bird. * @return If bird is colliding with the pipe
* @return If bird is colliding with the pipe
*/ */
public boolean collide (Bird bird) { public boolean collide (Bird bird) {
// Do not allow bird to jump over pipe // Do not allow bird to jump over pipe
@ -64,8 +63,7 @@ public class Pipe extends HasPosition {
/** /**
* Set's pipe's y-coordinate (for bottom pipes) * Set's pipe's y-coordinate (for bottom pipes)
* * @param newY New y-coordinate
* @param newY New y-coordinate
*/ */
public void setY (int newY) { public void setY (int newY) {
y = newY; y = newY;

View File

@ -1,14 +1,15 @@
package com.example.flappybird; /** /**
* Sprites.java * Sprites.java
* Cuts up the main sprite sheet * Cuts up the main sprite sheet
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.io.IOException; import java.io.IOException;
import java.io.File;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
@ -18,14 +19,13 @@ public class Sprites {
// Resize factor to match frame size // Resize factor to match frame size
private static final double RESIZE_FACTOR = 2.605; private static final double RESIZE_FACTOR = 2.605;
private static BufferedImage spriteSheet = null; // HashMap of texture objects
private static final HashMap<String, Texture> textures = new HashMap<String, Texture>();
// HashMap of texture objects
private static HashMap<String, Texture> textures = new HashMap<String, Texture>();
public Sprites () { public Sprites () {
// Try to load sprite sheet, exit program if cannot // Try to load sprite sheet, exit program if cannot
try { BufferedImage spriteSheet = null;
try {
String fontPath = "/res/img/spriteSheet.png"; String fontPath = "/res/img/spriteSheet.png";
URL fontUrl = this.getClass().getResource(fontPath); URL fontUrl = this.getClass().getResource(fontPath);
assert fontUrl != null; assert fontUrl != null;

View File

@ -1,10 +1,12 @@
package com.example.flappybird; /** /**
* Texture.java * Texture.java
* Stores data for game textures * Stores data for game textures
* *
* @author Paul Krishnamurthy * @author Paul Krishnamurthy
*/ */
package com.example.flappybird;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.Rectangle; import java.awt.Rectangle;
@ -36,6 +38,5 @@ public class Texture extends HasPosition {
public Rectangle getRect () { public Rectangle getRect () {
return rect; return rect;
} }
} }

View File

@ -41,16 +41,15 @@ public abstract class GameState {
protected int score; // Player score protected int score; // Player score
protected int pipeDistTracker; // Distance between pipes protected int pipeDistTracker; // Distance between pipes
protected boolean inStartGameState = false; // To show instructions scren
protected Point clickedPoint = new Point(-1, -1); // Store point when player clicks
protected boolean scoreWasGreater; // If score was greater than previous highscore protected boolean scoreWasGreater; // If score was greater than previous highscore
protected String medal; // Medal to be awarded after each game
protected Point clickedPoint = new Point(-1, -1); // Store point when player clicks
public static ArrayList<Pipe> pipes; // Arraylist of Pipe objects public static ArrayList<Pipe> pipes; // Arraylist of Pipe objects
protected static boolean darkTheme; // Boolean to show dark or light screen protected static boolean darkTheme; // Boolean to show dark or light screen
protected static Bird gameBird; protected static Bird gameBird;
protected final static Highscore highscore = new Highscore();
public GamePanel gamePanel; public GamePanel gamePanel;

View File

@ -2,6 +2,7 @@ package com.example.flappybird.states;
import com.example.flappybird.FlappyBird; import com.example.flappybird.FlappyBird;
import com.example.flappybird.GamePanel; import com.example.flappybird.GamePanel;
import com.example.flappybird.Highscore;
import com.example.flappybird.Pipe; import com.example.flappybird.Pipe;
import javax.swing.*; import javax.swing.*;
@ -10,13 +11,16 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
public class PlayState extends GameState { public class PlayState extends GameState {
protected boolean inStartGameState = false; // To show instructions screen
protected String medal; // Medal to be awarded after each game
protected final Highscore highscore = new Highscore();
public PlayState(GamePanel panel) { public PlayState(GamePanel panel) {
super(panel); super(panel);
} }
public void startGameScreen (Graphics g) { public void startGameScreen (Graphics g) {
// Set bird's new position // Set bird's new position
gameBird.setGameStartPos(); gameBird.setGameStartPos();
@ -29,7 +33,6 @@ public class PlayState extends GameState {
g.drawImage(textures.get("instructions").getImage(), g.drawImage(textures.get("instructions").getImage(),
textures.get("instructions").getX(), textures.get("instructions").getX(),
textures.get("instructions").getY(), null); textures.get("instructions").getY(), null);
} }
/** /**
@ -159,7 +162,7 @@ public class PlayState extends GameState {
if (gameBird.isAlive()) { if (gameBird.isAlive()) {
if (p.collide(gameBird)) { if (p.collide(gameBird)) {
// Kill bird and play sound // Kill bird and play sound
gameBird.kill(); gameBird.killBird();
audio.hit(); audio.hit();
} else { } else {
@ -245,7 +248,7 @@ public class PlayState extends GameState {
} else { } else {
// Start game // Start game
pipeHandler(g); pipeHandler(g);
gameBird.inGame(); gameBird.inGameBorders();
} }
drawBase(g); // Draw base over pipes drawBase(g); // Draw base over pipes
@ -300,12 +303,10 @@ public class PlayState extends GameState {
// On game over screen, allow restart and leaderboard buttons // On game over screen, allow restart and leaderboard buttons
if (isTouching(textures.get("playButton").getRect())) { if (isTouching(textures.get("playButton").getRect())) {
inStartGameState = true; inStartGameState = true;
gamePanel.setGameState(new PlayState(gamePanel)); gamePanel.setGameState(this);
restart();
gameBird.setGameStartPos(); gameBird.setGameStartPos();
restart();
} else if (isTouching(textures.get("leaderboard").getRect())) { } else if (isTouching(textures.get("leaderboard").getRect())) {
// Dummy message // Dummy message
JOptionPane.showMessageDialog(gamePanel, JOptionPane.showMessageDialog(gamePanel,
"We can't access the leaderboard right now!", "We can't access the leaderboard right now!",