finish big refactorings
This commit is contained in:
parent
8b0cdf6963
commit
4df15dc254
@ -5,6 +5,8 @@ package com.example.flappybird; /**
|
|||||||
* @author Paul Krishnamurthy
|
* @author Paul Krishnamurthy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
@ -127,7 +129,7 @@ public class Bird extends HasPosition {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Play audio and set state to dead
|
// Play audio and set state to dead
|
||||||
GamePanel.audio.hit();
|
GameState.audio.hit();
|
||||||
isAlive = false;
|
isAlive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,19 +41,14 @@ public class FlappyBird extends JFrame implements ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void actionPerformed (ActionEvent e) {
|
public void actionPerformed (ActionEvent e) {
|
||||||
|
|
||||||
if (game != null && game.ready) {
|
if (game != null && game.ready) {
|
||||||
game.repaint();
|
game.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
FlappyBird game = new FlappyBird();
|
FlappyBird game = new FlappyBird();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ package com.example.flappybird; /**
|
|||||||
* @author Paul Krishnamurthy
|
* @author Paul Krishnamurthy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import com.example.flappybird.states.GameState;
|
||||||
|
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.*;
|
||||||
@ -19,77 +22,30 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
public class GamePanel extends JPanel implements KeyListener, MouseListener {
|
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
|
// Textures
|
||||||
public static HashMap<String, Texture> textures = new Sprites().getGameTextures();
|
private GameState gameState;
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
public boolean ready = false; // If game has loaded
|
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 () {
|
public GamePanel () {
|
||||||
|
setGameState(new MenuState(this));
|
||||||
|
|
||||||
rand = new Random();
|
// Make the panel focusable
|
||||||
|
setFocusable(true);
|
||||||
|
requestFocusInWindow();
|
||||||
|
|
||||||
// Try to load ttf file
|
gameState.restart(); // Reset game variables
|
||||||
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
|
|
||||||
|
|
||||||
// Input listeners
|
// Input listeners
|
||||||
addKeyListener(this);
|
addKeyListener(this);
|
||||||
addMouseListener(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() {
|
public void addNotify() {
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
requestFocus();
|
requestFocusInWindow(); // Ensures the panel gains focus
|
||||||
ready = true;
|
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
|
@Override
|
||||||
public void paintComponent (Graphics g) {
|
public void paintComponent (Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
|
gameState.renderGameState(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...");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -517,32 +70,9 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
|
|||||||
public void keyTyped (KeyEvent e) {}
|
public void keyTyped (KeyEvent e) {}
|
||||||
public void keyReleased (KeyEvent e) {}
|
public void keyReleased (KeyEvent e) {}
|
||||||
|
|
||||||
public void keyPressed (KeyEvent e) {
|
public void keyPressed(KeyEvent e) {
|
||||||
|
System.out.println("Key pressed: " + e.getKeyCode());
|
||||||
int keyCode = e.getKeyCode();
|
gameState.handleKeyboardEvent(e);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
@ -554,71 +84,9 @@ public class GamePanel extends JPanel implements KeyListener, MouseListener {
|
|||||||
public void mouseReleased (MouseEvent e) {}
|
public void mouseReleased (MouseEvent e) {}
|
||||||
public void mouseClicked (MouseEvent e) {}
|
public void mouseClicked (MouseEvent e) {}
|
||||||
|
|
||||||
public void mousePressed (MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
|
System.out.println("Mouse clicked at: " + e.getPoint());
|
||||||
// Save clicked point
|
gameState.handleMouseEvent(e);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ public class Highscore {
|
|||||||
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;
|
||||||
|
|
||||||
static {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user