finish big refactorings
This commit is contained in:
		@@ -5,6 +5,8 @@ package com.example.flappybird; /**
 | 
			
		||||
 * @author  Paul Krishnamurthy
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.states.GameState;
 | 
			
		||||
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.geom.AffineTransform;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
@@ -127,7 +129,7 @@ public class Bird extends HasPosition {
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			// Play audio and set state to dead
 | 
			
		||||
			GamePanel.audio.hit();
 | 
			
		||||
			GameState.audio.hit();
 | 
			
		||||
			isAlive = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,19 +41,14 @@ public class FlappyBird extends JFrame implements ActionListener {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void actionPerformed (ActionEvent e) {
 | 
			
		||||
 | 
			
		||||
		if (game != null && game.ready) {
 | 
			
		||||
			game.repaint();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public static void main(String[] args) {
 | 
			
		||||
 | 
			
		||||
		FlappyBird game = new FlappyBird();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,9 @@ package com.example.flappybird; /**
 | 
			
		||||
 * @author  Paul Krishnamurthy
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.states.GameState;
 | 
			
		||||
import com.example.flappybird.states.MenuState;
 | 
			
		||||
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
@@ -19,77 +22,30 @@ import java.awt.image.BufferedImage;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
 | 
			
		||||
public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
 | 
			
		||||
	private Random rand;
 | 
			
		||||
	private Calendar cal;
 | 
			
		||||
	
 | 
			
		||||
	////////////////////
 | 
			
		||||
	// Game variables //
 | 
			
		||||
	////////////////////
 | 
			
		||||
	
 | 
			
		||||
	// Fonts
 | 
			
		||||
	private Font flappyFontBase, 
 | 
			
		||||
				 flappyFontReal, 
 | 
			
		||||
				 flappyScoreFont,
 | 
			
		||||
				 flappyMiniFont = null;
 | 
			
		||||
 | 
			
		||||
	// Textures
 | 
			
		||||
	public static HashMap<String, Texture> textures = new Sprites().getGameTextures();	
 | 
			
		||||
	
 | 
			
		||||
	// Moving base effect
 | 
			
		||||
	private static int baseSpeed    = 2;
 | 
			
		||||
	private static int[] baseCoords = { 0, 435 };
 | 
			
		||||
 | 
			
		||||
	// Game states
 | 
			
		||||
	final static int MENU = 0;
 | 
			
		||||
	final static int GAME = 1;
 | 
			
		||||
	private int gameState = MENU;  
 | 
			
		||||
 | 
			
		||||
	private int score;           // Player score
 | 
			
		||||
	private int pipeDistTracker; // Distance between pipes
 | 
			
		||||
	private GameState gameState;
 | 
			
		||||
	
 | 
			
		||||
	public boolean ready = false;                   // If game has loaded
 | 
			
		||||
	private boolean inStartGameState = false;       // To show instructions scren
 | 
			
		||||
	private Point clickedPoint = new Point(-1, -1); // Store point when player clicks 
 | 
			
		||||
	private boolean scoreWasGreater;                // If score was greater than previous highscore
 | 
			
		||||
	private boolean darkTheme;                      // Boolean to show dark or light screen
 | 
			
		||||
	private String randomBird;                      // Random bird color
 | 
			
		||||
	private String medal;                           // Medal to be awarded after each game
 | 
			
		||||
	public ArrayList<Pipe> pipes;                   // Arraylist of Pipe objects
 | 
			
		||||
 | 
			
		||||
	private Bird gameBird;
 | 
			
		||||
	private Highscore highscore = new Highscore();
 | 
			
		||||
	public static Audio audio   = new Audio();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public GamePanel () {
 | 
			
		||||
		setGameState(new MenuState(this));
 | 
			
		||||
 | 
			
		||||
		rand = new Random();
 | 
			
		||||
		// Make the panel focusable
 | 
			
		||||
		setFocusable(true);
 | 
			
		||||
		requestFocusInWindow();
 | 
			
		||||
 | 
			
		||||
		// Try to load ttf file
 | 
			
		||||
		try {
 | 
			
		||||
			InputStream is = new BufferedInputStream(this.getClass().getResourceAsStream("/res/fonts/flappy-font.ttf"));
 | 
			
		||||
			flappyFontBase = Font.createFont(Font.TRUETYPE_FONT, is);
 | 
			
		||||
 | 
			
		||||
			// Header and sub-header fonts
 | 
			
		||||
			flappyScoreFont = flappyFontBase.deriveFont(Font.PLAIN, 50);
 | 
			
		||||
			flappyFontReal  = flappyFontBase.deriveFont(Font.PLAIN, 20);
 | 
			
		||||
			flappyMiniFont  = flappyFontBase.deriveFont(Font.PLAIN, 15);
 | 
			
		||||
 | 
			
		||||
		} catch (Exception ex) {
 | 
			
		||||
 | 
			
		||||
			// Exit is font cannot be loaded
 | 
			
		||||
			ex.printStackTrace();
 | 
			
		||||
			System.err.println("Could not load Flappy Font!");
 | 
			
		||||
			System.exit(-1);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		restart(); // Reset game variables
 | 
			
		||||
		gameState.restart(); // Reset game variables
 | 
			
		||||
 | 
			
		||||
		// Input listeners
 | 
			
		||||
		addKeyListener(this);
 | 
			
		||||
		addMouseListener(this);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setGameState(GameState state) {
 | 
			
		||||
		System.out.println("Switching to state: " + state.getClass().getName());
 | 
			
		||||
		this.gameState = state;
 | 
			
		||||
		repaint();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -97,417 +53,14 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
	 */
 | 
			
		||||
	public void addNotify() {
 | 
			
		||||
		super.addNotify();
 | 
			
		||||
		requestFocus();
 | 
			
		||||
		requestFocusInWindow(); // Ensures the panel gains focus
 | 
			
		||||
		ready = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Restarts game by resetting game variables
 | 
			
		||||
	 */
 | 
			
		||||
	public void restart () {
 | 
			
		||||
 | 
			
		||||
		// Reset game statistics
 | 
			
		||||
		score            = 0;
 | 
			
		||||
		pipeDistTracker  = 0;
 | 
			
		||||
		scoreWasGreater  = false;
 | 
			
		||||
 | 
			
		||||
		// Get current hour with Calendar
 | 
			
		||||
		// If it is past noon, use the dark theme
 | 
			
		||||
		cal = Calendar.getInstance();
 | 
			
		||||
		int currentHour = cal.get(Calendar.HOUR_OF_DAY);
 | 
			
		||||
 | 
			
		||||
		// Array of bird colors
 | 
			
		||||
		String[] birds = new String[] {
 | 
			
		||||
			"yellow",
 | 
			
		||||
			"blue",
 | 
			
		||||
			"red"
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// Set random scene assets
 | 
			
		||||
		darkTheme = currentHour > 12; // If we should use the dark theme
 | 
			
		||||
		randomBird = birds[rand.nextInt(3)]; // Random bird color
 | 
			
		||||
 | 
			
		||||
		// Game bird
 | 
			
		||||
		gameBird = new Bird(randomBird, 172, 250, new BufferedImage[] {
 | 
			
		||||
			textures.get(randomBird + "Bird1").getImage(),
 | 
			
		||||
			textures.get(randomBird + "Bird2").getImage(),
 | 
			
		||||
			textures.get(randomBird + "Bird3").getImage()
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Remove old pipes
 | 
			
		||||
		pipes = new ArrayList<Pipe>();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if point is in rectangle
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param      r     Rectangle
 | 
			
		||||
	 * @return           Boolean if point collides with rectangle
 | 
			
		||||
	 */
 | 
			
		||||
	private boolean isTouching (Rectangle r) {
 | 
			
		||||
		return r.contains(clickedPoint);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void paintComponent (Graphics g) {
 | 
			
		||||
		super.paintComponent(g);
 | 
			
		||||
 | 
			
		||||
		// Set font and color
 | 
			
		||||
		g.setFont(flappyFontReal);
 | 
			
		||||
		g.setColor(Color.white);
 | 
			
		||||
 | 
			
		||||
		// Only move screen if bird is alive
 | 
			
		||||
		if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
			// Move base
 | 
			
		||||
			baseCoords[0] = baseCoords[0] - baseSpeed < -435 ? 435 : baseCoords[0] - baseSpeed;
 | 
			
		||||
			baseCoords[1] = baseCoords[1] - baseSpeed < -435 ? 435 : baseCoords[1] - baseSpeed;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Background
 | 
			
		||||
		g.drawImage(darkTheme ? textures.get("background2").getImage() : 
 | 
			
		||||
			textures.get("background1").getImage(), 0, 0, null);
 | 
			
		||||
 | 
			
		||||
		// Draw bird
 | 
			
		||||
		gameBird.renderBird(g);
 | 
			
		||||
 | 
			
		||||
		switch (gameState) {
 | 
			
		||||
 | 
			
		||||
			case MENU:
 | 
			
		||||
 | 
			
		||||
				drawBase(g);
 | 
			
		||||
				drawMenu(g);
 | 
			
		||||
 | 
			
		||||
				gameBird.menuFloat();
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case GAME:
 | 
			
		||||
 | 
			
		||||
				if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
					// Start at instructions state
 | 
			
		||||
					if (inStartGameState) {
 | 
			
		||||
						startGameScreen(g);
 | 
			
		||||
 | 
			
		||||
					} else {
 | 
			
		||||
						// Start game
 | 
			
		||||
						pipeHandler(g);
 | 
			
		||||
						gameBird.inGame();
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					drawBase(g);                      // Draw base over pipes
 | 
			
		||||
					drawScore(g, score, false, 0, 0); // Draw player score
 | 
			
		||||
 | 
			
		||||
				} else {
 | 
			
		||||
 | 
			
		||||
					pipeHandler(g);
 | 
			
		||||
					drawBase(g);
 | 
			
		||||
 | 
			
		||||
					// Draw game over assets
 | 
			
		||||
					gameOver(g);
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/////////////////////////
 | 
			
		||||
	// All drawing methods //
 | 
			
		||||
	/////////////////////////
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Draws a string centered based on given restrictions
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param s     String to be drawn
 | 
			
		||||
	 * @param w     Constraining width
 | 
			
		||||
	 * @param h     Constraining height
 | 
			
		||||
	 * @param y     Fixed y-coordiate
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawCentered (String s, int w, int h, int y, Graphics g) {
 | 
			
		||||
		FontMetrics fm = g.getFontMetrics();
 | 
			
		||||
 | 
			
		||||
		// Calculate x-coordinate based on string length and width
 | 
			
		||||
		int x = (w - fm.stringWidth(s)) / 2;
 | 
			
		||||
		g.drawString(s, x, y);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Needs to be called differently based on screen
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawBase (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Moving base effect
 | 
			
		||||
		g.drawImage(textures.get("base").getImage(), baseCoords[0], textures.get("base").getY(), null);
 | 
			
		||||
		g.drawImage(textures.get("base").getImage(), baseCoords[1], textures.get("base").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	////////////////
 | 
			
		||||
	// Menuscreen //
 | 
			
		||||
	////////////////
 | 
			
		||||
 | 
			
		||||
	private void drawMenu (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Title
 | 
			
		||||
		g.drawImage(textures.get("titleText").getImage(), 
 | 
			
		||||
			textures.get("titleText").getX(), 
 | 
			
		||||
			textures.get("titleText").getY(), null);
 | 
			
		||||
 | 
			
		||||
		// Buttons
 | 
			
		||||
		g.drawImage(textures.get("playButton").getImage(),
 | 
			
		||||
			textures.get("playButton").getX(),
 | 
			
		||||
			textures.get("playButton").getY(), null);
 | 
			
		||||
		g.drawImage(textures.get("leaderboard").getImage(),
 | 
			
		||||
			textures.get("leaderboard").getX(),
 | 
			
		||||
			textures.get("leaderboard").getY(), null);
 | 
			
		||||
		g.drawImage(textures.get("rateButton").getImage(),
 | 
			
		||||
			textures.get("rateButton").getX(),
 | 
			
		||||
			textures.get("rateButton").getY(), null);
 | 
			
		||||
 | 
			
		||||
		// Credits :p
 | 
			
		||||
		drawCentered("Created by Paul Krishnamurthy", FlappyBird.WIDTH, FlappyBird.HEIGHT, 600, g);
 | 
			
		||||
		g.setFont(flappyMiniFont); // Change font
 | 
			
		||||
		drawCentered("www.PaulKr.com", FlappyBird.WIDTH, FlappyBird.HEIGHT, 630, g);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/////////////////
 | 
			
		||||
	// Game screen //
 | 
			
		||||
	/////////////////
 | 
			
		||||
 | 
			
		||||
	public void startGameScreen (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Set bird's new position
 | 
			
		||||
		gameBird.setGameStartPos();
 | 
			
		||||
 | 
			
		||||
		// Get ready text
 | 
			
		||||
		g.drawImage(textures.get("getReadyText").getImage(),
 | 
			
		||||
			textures.get("getReadyText").getX(),
 | 
			
		||||
			textures.get("getReadyText").getY(), null);
 | 
			
		||||
 | 
			
		||||
		// Instructions image
 | 
			
		||||
		g.drawImage(textures.get("instructions").getImage(), 
 | 
			
		||||
			textures.get("instructions").getX(),
 | 
			
		||||
			textures.get("instructions").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Aligns and draws score using image textures
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param mini     Boolean for drawing small or large numbers
 | 
			
		||||
	 * @param x        X-coordinate to draw for mini numbers
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawScore (Graphics g, int drawNum, boolean mini, int x, int y) {
 | 
			
		||||
	
 | 
			
		||||
		// Char array of digits
 | 
			
		||||
		char[] digits = ("" + drawNum).toCharArray();
 | 
			
		||||
		
 | 
			
		||||
		int digitCount = digits.length;
 | 
			
		||||
 | 
			
		||||
		// Calculate width for numeric textures
 | 
			
		||||
		int takeUp = 0;
 | 
			
		||||
		for (char digit : digits) {
 | 
			
		||||
 | 
			
		||||
			// Size to add varies based on texture
 | 
			
		||||
			if (mini) {
 | 
			
		||||
				takeUp += 18;
 | 
			
		||||
			} else {
 | 
			
		||||
				takeUp += digit == '1' ? 25 : 35;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Calculate x-coordinate
 | 
			
		||||
		int drawScoreX = mini ? (x - takeUp) : (FlappyBird.WIDTH / 2 - takeUp / 2);
 | 
			
		||||
 | 
			
		||||
		// Draw every digit
 | 
			
		||||
		for (int i = 0; i < digitCount; i++) {
 | 
			
		||||
			g.drawImage(textures.get((mini ? "mini-score-" : "score-") + digits[i]).getImage(), drawScoreX, (mini ? y : 60), null);
 | 
			
		||||
			
 | 
			
		||||
			// Size to add varies based on texture
 | 
			
		||||
			if (mini) {
 | 
			
		||||
				drawScoreX += 18;
 | 
			
		||||
			} else {
 | 
			
		||||
				drawScoreX += digits[i] == '1' ? 25 : 35;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Moves and repositions pipes
 | 
			
		||||
	 */
 | 
			
		||||
	public void pipeHandler (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Decrease distance between pipes
 | 
			
		||||
		if (gameBird.isAlive()) {
 | 
			
		||||
			pipeDistTracker --;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Initialize pipes as null
 | 
			
		||||
		Pipe topPipe = null;
 | 
			
		||||
		Pipe bottomPipe = null;
 | 
			
		||||
 | 
			
		||||
		// If there is no distance,
 | 
			
		||||
		// a new pipe is needed
 | 
			
		||||
		if (pipeDistTracker < 0) {
 | 
			
		||||
 | 
			
		||||
			// Reset distance
 | 
			
		||||
			pipeDistTracker = Pipe.PIPE_DISTANCE;
 | 
			
		||||
 | 
			
		||||
			for (Pipe p : pipes) {
 | 
			
		||||
 | 
			
		||||
				// If pipe is out of screen
 | 
			
		||||
				if (p.getX() < 0) {
 | 
			
		||||
					if (topPipe == null) { 
 | 
			
		||||
						topPipe = p;
 | 
			
		||||
						topPipe.canAwardPoint = true;
 | 
			
		||||
					}
 | 
			
		||||
					else if (bottomPipe == null) {
 | 
			
		||||
						bottomPipe = p; 
 | 
			
		||||
						topPipe.canAwardPoint = true;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Pipe currentPipe; // New pipe object for top and bottom pipes
 | 
			
		||||
 | 
			
		||||
			// Move and handle initial creation of top and bottom pipes
 | 
			
		||||
 | 
			
		||||
			if (topPipe == null) {
 | 
			
		||||
				currentPipe = new Pipe("top");
 | 
			
		||||
				topPipe = currentPipe;
 | 
			
		||||
				pipes.add(topPipe);
 | 
			
		||||
			} else {
 | 
			
		||||
				topPipe.reset();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (bottomPipe == null) {
 | 
			
		||||
				currentPipe = new Pipe("bottom");
 | 
			
		||||
				bottomPipe = currentPipe;
 | 
			
		||||
				pipes.add(bottomPipe);
 | 
			
		||||
 | 
			
		||||
				// Avoid doubling points when passing initial pipes
 | 
			
		||||
				bottomPipe.canAwardPoint = false;
 | 
			
		||||
			} else {
 | 
			
		||||
				bottomPipe.reset();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Set y-coordinate of bottom pipe based on 
 | 
			
		||||
			// y-coordinate of top pipe
 | 
			
		||||
			bottomPipe.setY(topPipe.getY() + Pipe.PIPE_SPACING);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Move and draw each pipe
 | 
			
		||||
 | 
			
		||||
		for (Pipe p : pipes) {
 | 
			
		||||
 | 
			
		||||
			// Move the pipe
 | 
			
		||||
			if (gameBird.isAlive()) {
 | 
			
		||||
				p.move();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Draw the top and bottom pipes
 | 
			
		||||
			if (p.getY() <= 0) {
 | 
			
		||||
				g.drawImage(textures.get("pipe-top").getImage(), p.getX(), p.getY(), null);
 | 
			
		||||
			} else {
 | 
			
		||||
				g.drawImage(textures.get("pipe-bottom").getImage(), p.getX(), p.getY(), null);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Check if bird hits pipes
 | 
			
		||||
			if (gameBird.isAlive()) {
 | 
			
		||||
				if (p.collide(gameBird)) {
 | 
			
		||||
					// Kill bird and play sound
 | 
			
		||||
					gameBird.kill();
 | 
			
		||||
					audio.hit();
 | 
			
		||||
				} else {
 | 
			
		||||
 | 
			
		||||
					// Checks if bird passes a pipe
 | 
			
		||||
					if (gameBird.getX() >= p.getX() + p.WIDTH / 2) {
 | 
			
		||||
 | 
			
		||||
						// Increase score and play sound
 | 
			
		||||
						if (p.canAwardPoint) {
 | 
			
		||||
							audio.point();
 | 
			
		||||
							score ++;
 | 
			
		||||
							p.canAwardPoint = false;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void gameOver (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Game over text
 | 
			
		||||
		g.drawImage(textures.get("gameOverText").getImage(), 
 | 
			
		||||
			textures.get("gameOverText").getX(), 
 | 
			
		||||
			textures.get("gameOverText").getY(), null);
 | 
			
		||||
 | 
			
		||||
		// Scorecard
 | 
			
		||||
		g.drawImage(textures.get("scoreCard").getImage(),
 | 
			
		||||
			textures.get("scoreCard").getX(),
 | 
			
		||||
			textures.get("scoreCard").getY(), null);
 | 
			
		||||
 | 
			
		||||
		// New highscore image
 | 
			
		||||
		if (scoreWasGreater) {
 | 
			
		||||
			g.drawImage(textures.get("newHighscore").getImage(),
 | 
			
		||||
				textures.get("newHighscore").getX(),
 | 
			
		||||
				textures.get("newHighscore").getY(), null);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Draw mini fonts for current and best scores
 | 
			
		||||
		drawScore(g, score, true, 303, 276);
 | 
			
		||||
		drawScore(g, highscore.bestScore(), true, 303, 330);
 | 
			
		||||
 | 
			
		||||
		// Handle highscore
 | 
			
		||||
		if (score > highscore.bestScore()) {
 | 
			
		||||
 | 
			
		||||
			// New best score
 | 
			
		||||
			scoreWasGreater = true;
 | 
			
		||||
			highscore.setNewBest(score); // Set in data file
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Medal
 | 
			
		||||
		if (score >= 10) { medal = "bronze"; }
 | 
			
		||||
		if (score >= 20) { medal = "silver"; }
 | 
			
		||||
		if (score >= 30) { medal = "gold"; }
 | 
			
		||||
		if (score >= 40) { medal = "platinum"; }
 | 
			
		||||
 | 
			
		||||
		// Only award a medal if they deserve it
 | 
			
		||||
		if (score > 9) {
 | 
			
		||||
			g.drawImage(textures.get(medal).getImage(),
 | 
			
		||||
				textures.get(medal).getX(),
 | 
			
		||||
				textures.get(medal).getY(), null);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Buttons
 | 
			
		||||
		g.drawImage(textures.get("playButton").getImage(),
 | 
			
		||||
			textures.get("playButton").getX(),
 | 
			
		||||
			textures.get("playButton").getY(), null);
 | 
			
		||||
		g.drawImage(textures.get("leaderboard").getImage(),
 | 
			
		||||
			textures.get("leaderboard").getX(),
 | 
			
		||||
			textures.get("leaderboard").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void openURL (String url) {
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			if (Desktop.isDesktopSupported()) {
 | 
			
		||||
				Desktop.getDesktop().browse(new URI(url));
 | 
			
		||||
			}
 | 
			
		||||
		} catch (Exception e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
			System.out.println("Sorry could not open URL...");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		gameState.renderGameState(g);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//////////////////////
 | 
			
		||||
@@ -517,32 +70,9 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
	public void keyTyped (KeyEvent e) {}
 | 
			
		||||
	public void keyReleased (KeyEvent e) {}
 | 
			
		||||
 | 
			
		||||
	public void keyPressed (KeyEvent e) {
 | 
			
		||||
 | 
			
		||||
		int keyCode = e.getKeyCode();
 | 
			
		||||
 | 
			
		||||
		if (gameState == MENU) {
 | 
			
		||||
 | 
			
		||||
			// Start game on 'enter' key
 | 
			
		||||
			if (keyCode == KeyEvent.VK_ENTER) {
 | 
			
		||||
				gameState = GAME;
 | 
			
		||||
				inStartGameState = true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else if (gameState == GAME && gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
			if (keyCode == KeyEvent.VK_SPACE) {
 | 
			
		||||
 | 
			
		||||
				// Exit instructions state
 | 
			
		||||
				if (inStartGameState) {
 | 
			
		||||
					inStartGameState = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Jump and play audio even if in instructions state
 | 
			
		||||
				gameBird.jump();
 | 
			
		||||
				audio.jump();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	public void keyPressed(KeyEvent e) {
 | 
			
		||||
		System.out.println("Key pressed: " + e.getKeyCode());
 | 
			
		||||
		gameState.handleKeyboardEvent(e);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	///////////////////
 | 
			
		||||
@@ -554,71 +84,9 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
 | 
			
		||||
	public void mouseReleased (MouseEvent e) {}
 | 
			
		||||
	public void mouseClicked (MouseEvent e) {}
 | 
			
		||||
 | 
			
		||||
	public void mousePressed (MouseEvent e) {
 | 
			
		||||
 | 
			
		||||
		// Save clicked point
 | 
			
		||||
		clickedPoint = e.getPoint();
 | 
			
		||||
 | 
			
		||||
		if (gameState == MENU) {
 | 
			
		||||
 | 
			
		||||
			if (isTouching(textures.get("playButton").getRect())) {
 | 
			
		||||
				gameState = GAME;
 | 
			
		||||
				inStartGameState = true;
 | 
			
		||||
 | 
			
		||||
			} else if (isTouching(textures.get("leaderboard").getRect())) {
 | 
			
		||||
 | 
			
		||||
				// Dummy message
 | 
			
		||||
				JOptionPane.showMessageDialog(this, 
 | 
			
		||||
					"We can't access the leaderboard right now!",
 | 
			
		||||
					"Oops!",
 | 
			
		||||
					JOptionPane.ERROR_MESSAGE);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
				if (isTouching(textures.get("rateButton").getRect())) {
 | 
			
		||||
					openURL("http://paulkr.com"); // Open website
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else if (gameState == GAME) {
 | 
			
		||||
 | 
			
		||||
			if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
				// Allow jump with clicks
 | 
			
		||||
				if (inStartGameState) {
 | 
			
		||||
					inStartGameState = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Jump and play sound
 | 
			
		||||
				gameBird.jump();
 | 
			
		||||
				audio.jump();
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
 | 
			
		||||
				// On game over screen, allow restart and leaderboard buttons
 | 
			
		||||
				if (isTouching(textures.get("playButton").getRect())) {
 | 
			
		||||
					inStartGameState = true;
 | 
			
		||||
					gameState = GAME;
 | 
			
		||||
					restart();
 | 
			
		||||
					gameBird.setGameStartPos();
 | 
			
		||||
 | 
			
		||||
				} else if (isTouching(textures.get("leaderboard").getRect())) {
 | 
			
		||||
 | 
			
		||||
					// Dummy message
 | 
			
		||||
					JOptionPane.showMessageDialog(this, 
 | 
			
		||||
						"We can't access the leaderboard right now!",
 | 
			
		||||
						"Oops!",
 | 
			
		||||
						JOptionPane.ERROR_MESSAGE);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	public void mousePressed(MouseEvent e) {
 | 
			
		||||
		System.out.println("Mouse clicked at: " + e.getPoint());
 | 
			
		||||
		gameState.handleMouseEvent(e);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ public class Highscore {
 | 
			
		||||
	private static final String FILE_PATH = "/res/data/highscore.dat";
 | 
			
		||||
 | 
			
		||||
	private static final URL dataURL = Highscore.class.getResource(FILE_PATH);
 | 
			
		||||
 | 
			
		||||
	private static final File dataFile;
 | 
			
		||||
 | 
			
		||||
	static {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,169 @@
 | 
			
		||||
package com.example.flappybird.states; /**
 | 
			
		||||
 * GamePanel.java
 | 
			
		||||
 * Main game panel
 | 
			
		||||
 *
 | 
			
		||||
 * @author  Paul Krishnamurthy
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.*;
 | 
			
		||||
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.KeyEvent;
 | 
			
		||||
import java.awt.event.MouseEvent;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.BufferedInputStream;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
public abstract class GameState {
 | 
			
		||||
	private final Random rand;
 | 
			
		||||
 | 
			
		||||
	////////////////////
 | 
			
		||||
	// Game variables //
 | 
			
		||||
	////////////////////
 | 
			
		||||
 | 
			
		||||
	// Fonts
 | 
			
		||||
	public static Font flappyFontBase;
 | 
			
		||||
	public static Font flappyFontReal;
 | 
			
		||||
	public static Font flappyScoreFont;
 | 
			
		||||
	public static Font flappyMiniFont = null;
 | 
			
		||||
 | 
			
		||||
	public static Audio audio   = new Audio();
 | 
			
		||||
 | 
			
		||||
	// Textures
 | 
			
		||||
	public static HashMap<String, Texture> textures = new Sprites().getGameTextures();
 | 
			
		||||
 | 
			
		||||
	protected static final int[] baseCoords = { 0, 435 };
 | 
			
		||||
 | 
			
		||||
	protected int score;           // Player score
 | 
			
		||||
	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 String medal;                           // Medal to be awarded after each game
 | 
			
		||||
	public static ArrayList<Pipe> pipes;                   // Arraylist of Pipe objects
 | 
			
		||||
 | 
			
		||||
	protected static boolean darkTheme;                      // Boolean to show dark or light screen
 | 
			
		||||
 | 
			
		||||
	protected static Bird gameBird;
 | 
			
		||||
	protected final static Highscore highscore = new Highscore();
 | 
			
		||||
 | 
			
		||||
	public GamePanel gamePanel;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public GameState(GamePanel panel) {
 | 
			
		||||
		this.gamePanel = panel;
 | 
			
		||||
		rand = new Random();
 | 
			
		||||
 | 
			
		||||
		// Try to load ttf file
 | 
			
		||||
		try {
 | 
			
		||||
			InputStream is = new BufferedInputStream(this.getClass().getResourceAsStream("/res/fonts/flappy-font.ttf"));
 | 
			
		||||
			flappyFontBase = Font.createFont(Font.TRUETYPE_FONT, is);
 | 
			
		||||
 | 
			
		||||
			// Header and sub-header fonts
 | 
			
		||||
			flappyScoreFont = flappyFontBase.deriveFont(Font.PLAIN, 50);
 | 
			
		||||
			flappyFontReal  = flappyFontBase.deriveFont(Font.PLAIN, 20);
 | 
			
		||||
			flappyMiniFont  = flappyFontBase.deriveFont(Font.PLAIN, 15);
 | 
			
		||||
 | 
			
		||||
		} catch (Exception ex) {
 | 
			
		||||
 | 
			
		||||
			// Exit is font cannot be loaded
 | 
			
		||||
			ex.printStackTrace();
 | 
			
		||||
			System.err.println("Could not load Flappy Font!");
 | 
			
		||||
			System.exit(-1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Restarts game by resetting game variables
 | 
			
		||||
	 */
 | 
			
		||||
	public void restart () {
 | 
			
		||||
 | 
			
		||||
		// Reset game statistics
 | 
			
		||||
		score            = 0;
 | 
			
		||||
		pipeDistTracker  = 0;
 | 
			
		||||
		scoreWasGreater  = false;
 | 
			
		||||
 | 
			
		||||
		// Get current hour with Calendar
 | 
			
		||||
		// If it is past noon, use the dark theme
 | 
			
		||||
		Calendar cal = Calendar.getInstance();
 | 
			
		||||
		int currentHour = cal.get(Calendar.HOUR_OF_DAY);
 | 
			
		||||
 | 
			
		||||
		// Array of bird colors
 | 
			
		||||
		String[] birds = new String[] {
 | 
			
		||||
			"yellow",
 | 
			
		||||
			"blue",
 | 
			
		||||
			"red"
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// Set random scene assets
 | 
			
		||||
		darkTheme = currentHour > 12; // If we should use the dark theme
 | 
			
		||||
		// Random bird color
 | 
			
		||||
		String randomBird = birds[rand.nextInt(3)]; // Random bird color
 | 
			
		||||
 | 
			
		||||
		// Game bird
 | 
			
		||||
		gameBird = new Bird(randomBird, 172, 250, new BufferedImage[] {
 | 
			
		||||
			textures.get(randomBird + "Bird1").getImage(),
 | 
			
		||||
			textures.get(randomBird + "Bird2").getImage(),
 | 
			
		||||
			textures.get(randomBird + "Bird3").getImage()
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Remove old pipes
 | 
			
		||||
		pipes = new ArrayList<Pipe>();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Checks if point is in rectangle
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param      r     Rectangle
 | 
			
		||||
	 * @return           Boolean if point collides with rectangle
 | 
			
		||||
	 */
 | 
			
		||||
	protected boolean isTouching (Rectangle r) {
 | 
			
		||||
		return r.contains(clickedPoint);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void prepareScreen(Graphics g) {
 | 
			
		||||
		// Set font and color
 | 
			
		||||
		g.setFont(flappyFontReal);
 | 
			
		||||
		g.setColor(Color.white);
 | 
			
		||||
 | 
			
		||||
		// Only move screen if bird is alive
 | 
			
		||||
		if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
			// Move base
 | 
			
		||||
			// Moving base effect
 | 
			
		||||
			int baseSpeed = 2;
 | 
			
		||||
			baseCoords[0] = baseCoords[0] - baseSpeed < -435 ? 435 : baseCoords[0] - baseSpeed;
 | 
			
		||||
			baseCoords[1] = baseCoords[1] - baseSpeed < -435 ? 435 : baseCoords[1] - baseSpeed;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Background
 | 
			
		||||
		g.drawImage(darkTheme ? textures.get("background2").getImage() :
 | 
			
		||||
			textures.get("background1").getImage(), 0, 0, null);
 | 
			
		||||
 | 
			
		||||
		// Draw bird
 | 
			
		||||
		gameBird.renderBird(g);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public abstract void renderGameState(Graphics g);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Needs to be called differently based on screen
 | 
			
		||||
	 */
 | 
			
		||||
	public void drawBase (Graphics g) {
 | 
			
		||||
 | 
			
		||||
		// Moving base effect
 | 
			
		||||
		g.drawImage(textures.get("base").getImage(), baseCoords[0], textures.get("base").getY(), null);
 | 
			
		||||
		g.drawImage(textures.get("base").getImage(), baseCoords[1], textures.get("base").getY(), null);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public abstract void handleKeyboardEvent(KeyEvent e);
 | 
			
		||||
	public abstract void handleMouseEvent(MouseEvent e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,117 @@
 | 
			
		||||
package com.example.flappybird.states;
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.FlappyBird;
 | 
			
		||||
import com.example.flappybird.GamePanel;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.KeyEvent;
 | 
			
		||||
import java.awt.event.MouseEvent;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
 | 
			
		||||
public class MenuState extends GameState {
 | 
			
		||||
    public MenuState(GamePanel panel) {
 | 
			
		||||
        super(panel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void renderGameState(Graphics g) {
 | 
			
		||||
        prepareScreen(g);
 | 
			
		||||
 | 
			
		||||
        drawBase(g);
 | 
			
		||||
        drawMenu(g);
 | 
			
		||||
 | 
			
		||||
        gameBird.menuFloat();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Draws a string centered based on given restrictions
 | 
			
		||||
     *
 | 
			
		||||
     * @param s     String to be drawn
 | 
			
		||||
     * @param w     Constraining width
 | 
			
		||||
     * @param h     Constraining height
 | 
			
		||||
     * @param y     Fixed y-coordiate
 | 
			
		||||
     */
 | 
			
		||||
    public void drawCentered (String s, int w, int h, int y, Graphics g) {
 | 
			
		||||
        FontMetrics fm = g.getFontMetrics();
 | 
			
		||||
 | 
			
		||||
        // Calculate x-coordinate based on string length and width
 | 
			
		||||
        int x = (w - fm.stringWidth(s)) / 2;
 | 
			
		||||
        g.drawString(s, x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void drawMenu (Graphics g) {
 | 
			
		||||
        // Title
 | 
			
		||||
        g.drawImage(textures.get("titleText").getImage(),
 | 
			
		||||
                textures.get("titleText").getX(),
 | 
			
		||||
                textures.get("titleText").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // Buttons
 | 
			
		||||
        g.drawImage(textures.get("playButton").getImage(),
 | 
			
		||||
                textures.get("playButton").getX(),
 | 
			
		||||
                textures.get("playButton").getY(), null);
 | 
			
		||||
        g.drawImage(textures.get("leaderboard").getImage(),
 | 
			
		||||
                textures.get("leaderboard").getX(),
 | 
			
		||||
                textures.get("leaderboard").getY(), null);
 | 
			
		||||
        g.drawImage(textures.get("rateButton").getImage(),
 | 
			
		||||
                textures.get("rateButton").getX(),
 | 
			
		||||
                textures.get("rateButton").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // Credits :p
 | 
			
		||||
        drawCentered("Created by Paul Krishnamurthy", FlappyBird.WIDTH, FlappyBird.HEIGHT, 600, g);
 | 
			
		||||
        g.setFont(flappyMiniFont); // Change font
 | 
			
		||||
        drawCentered("www.PaulKr.com", FlappyBird.WIDTH, FlappyBird.HEIGHT, 630, g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to open the review url in default web browser
 | 
			
		||||
     */
 | 
			
		||||
    public void openReviewUrl() {
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            if (Desktop.isDesktopSupported()) {
 | 
			
		||||
                Desktop.getDesktop().browse(new URI("http://paulkr.com"));
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            System.out.println("Sorry could not open URL...");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handleKeyboardEvent(KeyEvent e) {
 | 
			
		||||
        int keyCode = e.getKeyCode();
 | 
			
		||||
        // Start game on 'enter' key
 | 
			
		||||
        if (keyCode == KeyEvent.VK_ENTER) {
 | 
			
		||||
            gamePanel.setGameState(new PlayState(gamePanel));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handleMouseEvent(MouseEvent e) {
 | 
			
		||||
        // Save clicked point
 | 
			
		||||
        clickedPoint = e.getPoint();
 | 
			
		||||
 | 
			
		||||
        if (isTouching(GameState.textures.get("playButton").getRect())) {
 | 
			
		||||
            gamePanel.setGameState(new PlayState(gamePanel));
 | 
			
		||||
 | 
			
		||||
        } else if (isTouching(GameState.textures.get("leaderboard").getRect())) {
 | 
			
		||||
            // Dummy message
 | 
			
		||||
            JOptionPane.showMessageDialog(gamePanel,
 | 
			
		||||
                    "We can't access the leaderboard right now!",
 | 
			
		||||
                    "Oops!",
 | 
			
		||||
                    JOptionPane.ERROR_MESSAGE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Rectangle rect = GameState.textures.get("playButton").getRect();
 | 
			
		||||
        System.out.println("Texture Rect: x=" + rect.getX() + ", y=" + rect.getY() +
 | 
			
		||||
                ", width=" + rect.getWidth() + ", height=" + rect.getHeight());
 | 
			
		||||
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
            if (isTouching(textures.get("rateButton").getRect())) {
 | 
			
		||||
                openReviewUrl(); // Open website
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,318 @@
 | 
			
		||||
package com.example.flappybird.states;
 | 
			
		||||
 | 
			
		||||
import com.example.flappybird.FlappyBird;
 | 
			
		||||
import com.example.flappybird.GamePanel;
 | 
			
		||||
import com.example.flappybird.Pipe;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.KeyEvent;
 | 
			
		||||
import java.awt.event.MouseEvent;
 | 
			
		||||
 | 
			
		||||
public class PlayState extends GameState {
 | 
			
		||||
 | 
			
		||||
    public PlayState(GamePanel panel) {
 | 
			
		||||
        super(panel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void startGameScreen (Graphics g) {
 | 
			
		||||
 | 
			
		||||
        // Set bird's new position
 | 
			
		||||
        gameBird.setGameStartPos();
 | 
			
		||||
 | 
			
		||||
        // Get ready text
 | 
			
		||||
        g.drawImage(textures.get("getReadyText").getImage(),
 | 
			
		||||
                textures.get("getReadyText").getX(),
 | 
			
		||||
                textures.get("getReadyText").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // Instructions image
 | 
			
		||||
        g.drawImage(textures.get("instructions").getImage(),
 | 
			
		||||
                textures.get("instructions").getX(),
 | 
			
		||||
                textures.get("instructions").getY(), null);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aligns and draws score using image textures
 | 
			
		||||
     *
 | 
			
		||||
     * @param mini     Boolean for drawing small or large numbers
 | 
			
		||||
     * @param x        X-coordinate to draw for mini numbers
 | 
			
		||||
     */
 | 
			
		||||
    public void drawScore (Graphics g, int drawNum, boolean mini, int x, int y) {
 | 
			
		||||
 | 
			
		||||
        // Char array of digits
 | 
			
		||||
        char[] digits = ("" + drawNum).toCharArray();
 | 
			
		||||
 | 
			
		||||
        int digitCount = digits.length;
 | 
			
		||||
 | 
			
		||||
        // Calculate width for numeric textures
 | 
			
		||||
        int takeUp = 0;
 | 
			
		||||
        for (char digit : digits) {
 | 
			
		||||
 | 
			
		||||
            // Size to add varies based on texture
 | 
			
		||||
            if (mini) {
 | 
			
		||||
                takeUp += 18;
 | 
			
		||||
            } else {
 | 
			
		||||
                takeUp += digit == '1' ? 25 : 35;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate x-coordinate
 | 
			
		||||
        int drawScoreX = mini ? (x - takeUp) : (FlappyBird.WIDTH / 2 - takeUp / 2);
 | 
			
		||||
 | 
			
		||||
        // Draw every digit
 | 
			
		||||
        for (int i = 0; i < digitCount; i++) {
 | 
			
		||||
            g.drawImage(textures.get((mini ? "mini-score-" : "score-") + digits[i]).getImage(), drawScoreX, (mini ? y : 60), null);
 | 
			
		||||
 | 
			
		||||
            // Size to add varies based on texture
 | 
			
		||||
            if (mini) {
 | 
			
		||||
                drawScoreX += 18;
 | 
			
		||||
            } else {
 | 
			
		||||
                drawScoreX += digits[i] == '1' ? 25 : 35;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves and repositions pipes
 | 
			
		||||
     */
 | 
			
		||||
    public void pipeHandler (Graphics g) {
 | 
			
		||||
 | 
			
		||||
        // Decrease distance between pipes
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
            pipeDistTracker --;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Initialize pipes as null
 | 
			
		||||
        Pipe topPipe = null;
 | 
			
		||||
        Pipe bottomPipe = null;
 | 
			
		||||
 | 
			
		||||
        // If there is no distance,
 | 
			
		||||
        // a new pipe is needed
 | 
			
		||||
        if (pipeDistTracker < 0) {
 | 
			
		||||
 | 
			
		||||
            // Reset distance
 | 
			
		||||
            pipeDistTracker = Pipe.PIPE_DISTANCE;
 | 
			
		||||
 | 
			
		||||
            for (Pipe p : pipes) {
 | 
			
		||||
 | 
			
		||||
                // If pipe is out of screen
 | 
			
		||||
                if (p.getX() < 0) {
 | 
			
		||||
                    if (topPipe == null) {
 | 
			
		||||
                        topPipe = p;
 | 
			
		||||
                        topPipe.canAwardPoint = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (bottomPipe == null) {
 | 
			
		||||
                        bottomPipe = p;
 | 
			
		||||
                        topPipe.canAwardPoint = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Pipe currentPipe; // New pipe object for top and bottom pipes
 | 
			
		||||
 | 
			
		||||
            // Move and handle initial creation of top and bottom pipes
 | 
			
		||||
 | 
			
		||||
            if (topPipe == null) {
 | 
			
		||||
                currentPipe = new Pipe("top");
 | 
			
		||||
                topPipe = currentPipe;
 | 
			
		||||
                pipes.add(topPipe);
 | 
			
		||||
            } else {
 | 
			
		||||
                topPipe.reset();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (bottomPipe == null) {
 | 
			
		||||
                currentPipe = new Pipe("bottom");
 | 
			
		||||
                bottomPipe = currentPipe;
 | 
			
		||||
                pipes.add(bottomPipe);
 | 
			
		||||
 | 
			
		||||
                // Avoid doubling points when passing initial pipes
 | 
			
		||||
                bottomPipe.canAwardPoint = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                bottomPipe.reset();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set y-coordinate of bottom pipe based on
 | 
			
		||||
            // y-coordinate of top pipe
 | 
			
		||||
            bottomPipe.setY(topPipe.getY() + Pipe.PIPE_SPACING);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Move and draw each pipe
 | 
			
		||||
 | 
			
		||||
        for (Pipe p : pipes) {
 | 
			
		||||
 | 
			
		||||
            // Move the pipe
 | 
			
		||||
            if (gameBird.isAlive()) {
 | 
			
		||||
                p.move();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Draw the top and bottom pipes
 | 
			
		||||
            if (p.getY() <= 0) {
 | 
			
		||||
                g.drawImage(textures.get("pipe-top").getImage(), p.getX(), p.getY(), null);
 | 
			
		||||
            } else {
 | 
			
		||||
                g.drawImage(textures.get("pipe-bottom").getImage(), p.getX(), p.getY(), null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if bird hits pipes
 | 
			
		||||
            if (gameBird.isAlive()) {
 | 
			
		||||
                if (p.collide(gameBird)) {
 | 
			
		||||
                    // Kill bird and play sound
 | 
			
		||||
                    gameBird.kill();
 | 
			
		||||
                    audio.hit();
 | 
			
		||||
                } else {
 | 
			
		||||
 | 
			
		||||
                    // Checks if bird passes a pipe
 | 
			
		||||
                    if (gameBird.getX() >= p.getX() + p.WIDTH / 2) {
 | 
			
		||||
 | 
			
		||||
                        // Increase score and play sound
 | 
			
		||||
                        if (p.canAwardPoint) {
 | 
			
		||||
                            audio.point();
 | 
			
		||||
                            score ++;
 | 
			
		||||
                            p.canAwardPoint = false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void gameOver (Graphics g) {
 | 
			
		||||
 | 
			
		||||
        // Game over text
 | 
			
		||||
        g.drawImage(textures.get("gameOverText").getImage(),
 | 
			
		||||
                textures.get("gameOverText").getX(),
 | 
			
		||||
                textures.get("gameOverText").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // Scorecard
 | 
			
		||||
        g.drawImage(textures.get("scoreCard").getImage(),
 | 
			
		||||
                textures.get("scoreCard").getX(),
 | 
			
		||||
                textures.get("scoreCard").getY(), null);
 | 
			
		||||
 | 
			
		||||
        // New highscore image
 | 
			
		||||
        if (scoreWasGreater) {
 | 
			
		||||
            g.drawImage(textures.get("newHighscore").getImage(),
 | 
			
		||||
                    textures.get("newHighscore").getX(),
 | 
			
		||||
                    textures.get("newHighscore").getY(), null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Draw mini fonts for current and best scores
 | 
			
		||||
        drawScore(g, score, true, 303, 276);
 | 
			
		||||
        drawScore(g, highscore.bestScore(), true, 303, 330);
 | 
			
		||||
 | 
			
		||||
        // Handle highscore
 | 
			
		||||
        if (score > highscore.bestScore()) {
 | 
			
		||||
 | 
			
		||||
            // New best score
 | 
			
		||||
            scoreWasGreater = true;
 | 
			
		||||
            highscore.setNewBest(score); // Set in data file
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Medal
 | 
			
		||||
        if (score >= 10) { medal = "bronze"; }
 | 
			
		||||
        if (score >= 20) { medal = "silver"; }
 | 
			
		||||
        if (score >= 30) { medal = "gold"; }
 | 
			
		||||
        if (score >= 40) { medal = "platinum"; }
 | 
			
		||||
 | 
			
		||||
        // Only award a medal if they deserve it
 | 
			
		||||
        if (score > 9) {
 | 
			
		||||
            g.drawImage(textures.get(medal).getImage(),
 | 
			
		||||
                    textures.get(medal).getX(),
 | 
			
		||||
                    textures.get(medal).getY(), null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Buttons
 | 
			
		||||
        g.drawImage(textures.get("playButton").getImage(),
 | 
			
		||||
                textures.get("playButton").getX(),
 | 
			
		||||
                textures.get("playButton").getY(), null);
 | 
			
		||||
        g.drawImage(textures.get("leaderboard").getImage(),
 | 
			
		||||
                textures.get("leaderboard").getX(),
 | 
			
		||||
                textures.get("leaderboard").getY(), null);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void renderGameState(Graphics g) {
 | 
			
		||||
        prepareScreen(g);
 | 
			
		||||
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
            // Start at instructions state
 | 
			
		||||
            if (inStartGameState) {
 | 
			
		||||
                startGameScreen(g);
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                // Start game
 | 
			
		||||
                pipeHandler(g);
 | 
			
		||||
                gameBird.inGame();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            drawBase(g);                      // Draw base over pipes
 | 
			
		||||
            drawScore(g, score, false, 0, 0); // Draw player score
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            pipeHandler(g);
 | 
			
		||||
            drawBase(g);
 | 
			
		||||
 | 
			
		||||
            // Draw game over assets
 | 
			
		||||
            gameOver(g);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handleKeyboardEvent(KeyEvent e) {
 | 
			
		||||
        int keyCode = e.getKeyCode();
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
            if (keyCode == KeyEvent.VK_SPACE) {
 | 
			
		||||
 | 
			
		||||
                // Exit instructions state
 | 
			
		||||
                if (inStartGameState) {
 | 
			
		||||
                    inStartGameState = false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Jump and play audio even if in instructions state
 | 
			
		||||
                gameBird.jump();
 | 
			
		||||
                audio.jump();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handleMouseEvent(MouseEvent e) {
 | 
			
		||||
        // Save clicked point
 | 
			
		||||
        clickedPoint = e.getPoint();
 | 
			
		||||
 | 
			
		||||
        if (gameBird.isAlive()) {
 | 
			
		||||
 | 
			
		||||
            // Allow jump with clicks
 | 
			
		||||
            if (inStartGameState) {
 | 
			
		||||
                inStartGameState = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Jump and play sound
 | 
			
		||||
            gameBird.jump();
 | 
			
		||||
            audio.jump();
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            // On game over screen, allow restart and leaderboard buttons
 | 
			
		||||
            if (isTouching(textures.get("playButton").getRect())) {
 | 
			
		||||
                inStartGameState = true;
 | 
			
		||||
                gamePanel.setGameState(new PlayState(gamePanel));
 | 
			
		||||
                restart();
 | 
			
		||||
                gameBird.setGameStartPos();
 | 
			
		||||
 | 
			
		||||
            } else if (isTouching(textures.get("leaderboard").getRect())) {
 | 
			
		||||
 | 
			
		||||
                // Dummy message
 | 
			
		||||
                JOptionPane.showMessageDialog(gamePanel,
 | 
			
		||||
                        "We can't access the leaderboard right now!",
 | 
			
		||||
                        "Oops!",
 | 
			
		||||
                        JOptionPane.ERROR_MESSAGE);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user