In this article, we will build the famous Flappy Bird Game in Java with Swing. We all have played this game on our phones, here we will create the desktop version of this application. Flappy Bird is a game where the bird must keep flying in the air without hitting the ground or the obstacles in the way.
Project Overview: Flappy Bird Game in Java
Project Name: | Flappy Bird Game in Java |
Abstract: | It’s a GUI-based project used with the swing library to organize all the elements that work under the Flappy Bird Game. |
Language Used: | Java |
IDE: | VS Code |
Java version (Recommended): | Java SE 18.0. 2.1 |
Database: | None |
Type: | Desktop Application |
Recommended for: | Beginners of Java |
Time to build: | 1-2 hours |
What you will learn?
- Building logic with the help of functions, loops, conditionals, and variables
- Handling Classes and Object creations
- Java Swing and Java AWT for creating a user-friendly GUI
Features:
- Use the spacebar key to fly high
- Create obstacles and birds with the help of Java Swing
- Keep updating the current score and the high score as the bird passes by an obstacle
Complete Code for the Flappy Bird game in Java
To create the shape of the bird, wall, and background we have used these images (download below). Now, Create a folder for the project and add all the images in it. Create a file named Game.java and add the below lines of code to it.
Click here to download resources used in this game
To detect collision between the bird and the wall or ground, nested if-else conditions are used to compare each object’s coordinates. Appropriate comments are provided in the code for explanation.
import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.JPanel; import javax.swing.Timer; import java.awt.image.ImageObserver; import javax.swing.ImageIcon; import java.util.ArrayList; import java.util.List; import java.util.Random; // Bird class is used to create a bird object in the game and to move it around the screen class Bird extends GameObject { private ProxyImage proxyImage; // ProxyImage object used to load the image of the bird private Tube[] tube; // Array of Tube objects used to create the walls in the game // Constructor public Bird(int x, int y){ super(x, y); if(proxyImage == null) { proxyImage = new ProxyImage("bird.png"); // Load the image of the bird } this.image = proxyImage.loadImage().getImage(); this.width = image.getWidth(null); //Set the width and height of the bird this.height = image.getHeight(null); this.x -= width; // Adjust the x position of the bird this.y -= height; // Adjust the y position of the bird tube = new Tube[1]; // Create a new array of Tube objects tube[0] = new Tube(900, Window.HEIGHT - 60); // Create the first wall this.dy = 2; // Set the initial speed of the bird } // Method used to move the bird public void tick() { if(dy < 5) { // If the speed of the bird is less than 5 dy += 2; // Increase the speed of the bird } this.y += dy; // Move the bird down the screen tube[0].tick(); // Move the wall down the screen checkWindowBorder(); // Check if the bird has hit the top or bottom of the screen } public void jump() { if(dy > 0) { // If the speed of the bird is greater than 0 dy = 0; // Set the speed of the bird to 0 } dy -= 15; // Move the bird up the screen } // Method used to check if the bird has hit the top or bottom of the screen private void checkWindowBorder() { if(this.x > Window.WIDTH) { // If the bird has moved off the right side of the screen this.x = Window.WIDTH; // Set the x position of the bird to the right side of the screen } if(this.x < 0) { // If the bird has moved off the left side of the screen this.x = 0; // Set the x position of the bird to the left side of the screen } if(this.y > Window.HEIGHT - 50) { // If the bird has moved off the bottom of the screen this.y = Window.HEIGHT - 50; // Set the y position of the bird to the bottom of the screen } if(this.y < 0) { // If the bird has moved off the top of the screen this.y = 0; // Set the y position of the bird to the top of the screen } } // Method used to check if the bird has hit the wall public void render(Graphics2D g, ImageObserver obs) { g.drawImage(image, x, y, obs); // Draw the bird tube[0].render(g, obs); // Draw the wall } public Rectangle getBounds() { return new Rectangle(x, y, width, height); } } // Tube class is used to create a wall object in the game and to move it around the screen class TubeColumn { private int base = Window.HEIGHT - 60; private List<Tube> tubes; private Random random; private int points = 0; // Variable used to keep track of the score private int speed = 5; // Variable used to set the speed of the wall private int changeSpeed = speed; public TubeColumn() { tubes = new ArrayList<>(); random = new Random(); initTubes(); } // Method used to create the wall private void initTubes() { int last = base; int randWay = random.nextInt(10); // Create the first wall in the game and set the position of the wall to the right side of the screen for (int i = 0; i < 20; i++) { Tube tempTube = new Tube(900, last); // Create a new Tube object tempTube.setDx(speed); // Set the speed of the wall last = tempTube.getY() - tempTube.getHeight(); // Set the position of the wall if (i < randWay || i > randWay + 4) { // If the wall is not in the middle of the screen tubes.add(tempTube); // Add the wall to the array of Tube objects } } } // Method used to check the position of the walls and to create new walls public void tick() { for (int i = 0; i < tubes.size(); i++) { // Loop through the array of Tube objects tubes.get(i).tick(); // Get the position of the wall if (tubes.get(i).getX() < 0) { // If the wall has moved off the left side of the screen tubes.remove(tubes.get(i)); // Remove the wall from the array of Tube objects } } if (tubes.isEmpty()) { // If the array of Tube objects is empty this.points += 1; // Increase the score by 1 if (changeSpeed == points) { this.speed += 1; // Increase the speed of the wall by 1 changeSpeed += 5; } initTubes(); // Create a new wall } } // Method used to draw the walls public void render(Graphics2D g, ImageObserver obs) { for (int i = 0; i < tubes.size(); i++) { // Loop through the array of Tube objects tubes.get(i).render(g, obs); // Draw the wall } } public List<Tube> getTubes() { return tubes; } public void setTubes(List<Tube> tubes) { this.tubes = tubes; } public int getPoints() { return points; } public void setPoints(int points) { this.points = points; } } interface IStrategy { public void controller(Bird bird, KeyEvent kevent); public void controllerReleased(Bird bird, KeyEvent kevent); } // Controller class is used to control the movement of the bird class Controller implements IStrategy { public void controller(Bird bird, KeyEvent kevent) { } public void controllerReleased(Bird bird, KeyEvent kevent) { if(kevent.getKeyCode() == KeyEvent.VK_SPACE) { // If the space bar is pressed bird jumps bird.jump(); } } } interface IImage { public ImageIcon loadImage(); } // ProxyImage class is used to load the image of all the objects class ProxyImage implements IImage { private final String src; private RealImage realImage; public ProxyImage(String src) { this.src = src; } public ImageIcon loadImage() { if(realImage == null) { // If the image has not been loaded this.realImage = new RealImage(src); // Load the image } return this.realImage.loadImage(); } } class RealImage implements IImage { private final String src; private ImageIcon imageIcon; public RealImage(String src) { this.src = src; } @Override public ImageIcon loadImage() { if(imageIcon == null) { this.imageIcon = new ImageIcon(getClass().getResource(src)); } return imageIcon; } } // this class is used to create the window for the game abstract class GameObject { protected int x, y; protected int dx, dy; protected int width, height; protected Image image; public GameObject(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public int getDx() { return dx; } public int getDy() { return dy; } public int getWidth() { return width; } public int getHeight() { return height; } public Image getImage() { return image; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setDx(int dx) { this.dx = dx; } public void setDy(int dy) { this.dy = dy; } public void setWidth(int width) { this.width = width; } public void setHeight(int height) { this.height = height; } public void setImage(Image image) { this.image = image; } public abstract void tick(); public abstract void render(Graphics2D g, ImageObserver obs); } // this class is used to create the walls for the game class Tube extends GameObject { private ProxyImage proxyImage; public Tube(int x, int y) { super(x, y); if (proxyImage == null) { // If the image has not been loaded proxyImage = new ProxyImage("TubeBody.png"); // Load the image } this.image = proxyImage.loadImage().getImage(); // Get the image this.width = image.getWidth(null); // set the width of the image this.height = image.getHeight(null); // set the height of the image } @Override public void tick() { this.x -= dx; } @Override public void render(Graphics2D g, ImageObserver obs) { g.drawImage(image, x, y, obs); } public Rectangle getBounds() { return new Rectangle(x, y, width, height); } } // this class is used to create the background for the game class Game extends JPanel implements ActionListener { private boolean isRunning = false; // Variable used to check if the game is running private ProxyImage proxyImage; // Variable used to load the image private Image background; // Variable used to store the image private Bird bird; // Variable used to store the bird object private TubeColumn tubeColumn; // Variable used to store the wall object private int score; private int highScore; public Game() { proxyImage = new ProxyImage("background.jpg"); // Load the image background = proxyImage.loadImage().getImage(); // Get the image setFocusable(true); setDoubleBuffered(false); addKeyListener(new GameKeyAdapter()); Timer timer = new Timer(15, this); timer.start(); } @Override public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().sync(); // Synchronize the display on some systems if (isRunning) { bird.tick(); // Update the bird tubeColumn.tick(); // Update the wall checkColision(); // Check if the bird has collided with the wall score++; // Increase the score by 1 } repaint(); } @Override public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.drawImage(background, 0, 0, null); if (isRunning) { this.bird.render(g2, this); this.tubeColumn.render(g2, this); g2.setColor(Color.black); g.setFont(new Font("MV Boli", 1, 30)); g2.drawString("Current score: " + this.tubeColumn.getPoints(), 10, 50); } else { g2.setColor(Color.black); g.setFont(new Font("MV Boli", 1, 50)); g2.drawString("Press Enter to Start Game", Window.WIDTH / 2 - 350, Window.HEIGHT / 2); g2.setColor(Color.black); g.setFont(new Font("MV Boli", 1, 15)); } g2.setColor(Color.black); g.setFont(new Font("MV Boli", 1, 30)); g2.drawString("High Score: " + highScore, Window.WIDTH - 230, 50); g.dispose(); } private void restartGame() { if (!isRunning) { this.isRunning = true; this.bird = new Bird(Window.WIDTH / 2, Window.HEIGHT / 2); // Create the bird object in the middle of the screen this.tubeColumn = new TubeColumn(); // Create the wall object } } private void endGame() { this.isRunning = false; if (this.tubeColumn.getPoints() > highScore) { // If the current score is higher than the high score this.highScore = this.tubeColumn.getPoints(); // Set the high score to the current score } this.tubeColumn.setPoints(0); // Set the current score to 0 } private void checkColision() { Rectangle rectBird = this.bird.getBounds(); // Get the bounds of the bird Rectangle rectTube; // Create a variable to store the bounds of the wall for (int i = 0; i < this.tubeColumn.getTubes().size(); i++) { // Loop through all the walls Tube tempTube = this.tubeColumn.getTubes().get(i); // Get the current wall rectTube = tempTube.getBounds(); // Get the bounds of the current wall if (rectBird.intersects(rectTube)) { // If the bird has collided with the wall endGame(); // End the game } } } class GameKeyAdapter extends KeyAdapter { private final Controller controller; public GameKeyAdapter() { controller = new Controller(); } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { restartGame(); } } @Override public void keyReleased(KeyEvent e) { if (isRunning) { controller.controllerReleased(bird, e); } } } } class Window { public static int WIDTH = 900; // Set the width of the window public static int HEIGHT = 600; // Set the height of the window public Window(int width, int height, String title, Game game) { JFrame frame = new JFrame(); frame.add(game); frame.setTitle(title); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Close the window when the user clicks the close button frame.setMaximumSize(new Dimension(width, height)); // Set the maximum size of the window frame.setPreferredSize(new Dimension(width, height)); // Set the preferred size of the window frame.setMinimumSize(new Dimension(width, height)); frame.setLocationRelativeTo(null); frame.setResizable(false); frame.setVisible(true); } // Run the application from here public static void main(String[] args) { Game game = new Game(); try { javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(Window.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } java.awt.EventQueue.invokeLater(() -> { Window window = new Window(WIDTH, HEIGHT, "Flappy Bird", game); }); } }
Output:
Hope you enjoyed building this project. You can try changing the controls of the game or adding your own colors and changing the dimensions according to you.
Also Read:
- Dino Game in Java
- Java Games Code | Copy And Paste
- Supply Chain Management System in Java
- Survey Management System In Java
- Phone Book in Java
- Email Application in Java
- Inventory Management System Project in Java
- Blood Bank Management System Project in Java
- Electricity Bill Management System Project in Java
- CGPA Calculator App In Java
- Chat Application in Java
- 100+ Java Projects for Beginners 2023
- Airline Reservation System Project in Java
- Password and Notes Manager in Java
- GUI Number Guessing Game in Java
- How to create Notepad in Java?
- Memory Game in Java
- Simple Car Race Game in Java
- ATM program in Java
- Drawing Application In Java
- Tetris Game in Java
- Pong Game in Java
- Hospital Management System Project in Java
- Ludo Game in Java
- Restaurant Management System Project in Java
- Flappy Bird Game in Java
- ATM Simulator In Java
- Brick Breaker Game in Java
- Best Java Roadmap for Beginners 2023
- Snake Game in Java