杰瑞科技汇

Java如何实现Flappy Bird游戏?

Of course! Creating a Flappy Bird game in Java is a fantastic project for learning game development fundamentals. We'll build a simple, command-line version using Java's built-in libraries. This version will be runnable directly from your terminal or IDE without needing any external graphics libraries.

Java如何实现Flappy Bird游戏?-图1
(图片来源网络,侵删)

Here is a complete, step-by-step guide to creating Flappy Bird in Java.

Core Concepts We'll Use

  1. Swing: We'll use the JFrame class to create the main game window.
  2. Graphics & Graphics2D: We'll use the paintComponent method to draw all our game elements (bird, pipes, background) onto the screen.
  3. javax.swing.Timer: This is crucial for creating the game loop. It will call our update method at a regular interval (e.g., 60 times per second).
  4. Object-Oriented Programming (OOP): We'll create classes for Bird, Pipe, and the main Game itself to keep our code organized.
  5. Event Handling: We'll use a KeyListener to make the bird "flap" when the user presses the spacebar.

Step 1: Project Setup

  1. Create a new Java project in your favorite IDE (like IntelliJ, Eclipse, or VS Code).
  2. Create a new Java file named FlappyBird.java. This will be our main class.

Step 2: The Bird Class

This class will manage the bird's state: its position, velocity, and how it's drawn.

Create a new file named Bird.java.

// Bird.java
import java.awt.*;
public class Bird {
    private int x, y;
    private int radius;
    private int velocity;
    private final int gravity = 1;
    private final int jumpStrength = -15;
    public Bird(int x, int y) {
        this.x = x;
        this.y = y;
        this.radius = 15;
        this.velocity = 0;
    }
    public void update() {
        velocity += gravity;
        y += velocity;
    }
    public void jump() {
        velocity = jumpStrength;
    }
    public void draw(Graphics g) {
        g.setColor(Color.YELLOW);
        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
        // Draw a simple eye
        g.setColor(Color.BLACK);
        g.fillOval(x + 5, y - 5, 5, 5);
    }
    // --- Getters for Collision Detection ---
    public int getX() { return x; }
    public int getY() { return y; }
    public int getRadius() { return radius; }
}

Step 3: The Pipe Class

This class will represent a pair of pipes (top and bottom) that move across the screen.

Java如何实现Flappy Bird游戏?-图2
(图片来源网络,侵删)

Create a new file named Pipe.java.

// Pipe.java
import java.awt.*;
public class Pipe {
    private int x;
    private int topHeight;
    private int gap;
    private final int width = 50;
    private final int speed = 5;
    public Pipe(int x, int topHeight, int gap) {
        this.x = x;
        this.topHeight = topHeight;
        this.gap = gap;
    }
    public void update() {
        x -= speed;
    }
    public void draw(Graphics g) {
        g.setColor(Color.GREEN.darker());
        // Top pipe
        g.fillRect(x, 0, width, topHeight);
        // Bottom pipe
        g.fillRect(x, topHeight + gap, width, 600 - (topHeight + gap));
    }
    // --- Getters for Collision Detection ---
    public int getX() { return x; }
    public int getWidth() { return width; }
    public int getTopHeight() { return topHeight; }
    public int getGap() { return gap; }
    public int getBottomPipeY() { return topHeight + gap; }
}

Step 4: The Main FlappyBird Game Class

This is where everything comes together. It will contain the game loop, handle user input, and manage the game state.

Replace the content of FlappyBird.java with the following code. The comments explain each part in detail.

// FlappyBird.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
public class FlappyBird extends JPanel implements ActionListener, KeyListener {
    // --- Game Constants ---
    private final int WIDTH = 400;
    private final int HEIGHT = 600;
    private final int PIPE_GAP = 150;
    private final int PIPE_SPACING = 300; // Space between pipes
    private final int BIRD_START_X = 100;
    private final int BIRD_START_Y = HEIGHT / 2;
    // --- Game Objects ---
    private Bird bird;
    private ArrayList<Pipe> pipes;
    private Random random;
    // --- Game State ---
    private int score;
    private boolean gameOver;
    private Timer gameTimer;
    public FlappyBird() {
        // --- Setup Panel ---
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(new Color(135, 206, 235)); // Sky blue
        setFocusable(true); // Allows the panel to receive key events
        addKeyListener(this);
        // --- Initialize Game ---
        resetGame();
    }
    private void resetGame() {
        bird = new Bird(BIRD_START_X, BIRD_START_Y);
        pipes = new ArrayList<>();
        random = new Random();
        score = 0;
        gameOver = false;
        // Create initial pipes
        for (int i = 0; i < 3; i++) {
            int pipeX = WIDTH + i * PIPE_SPACING;
            int topPipeHeight = random.nextInt(HEIGHT - PIPE_GAP - 100) + 50;
            pipes.add(new Pipe(pipeX, topPipeHeight, PIPE_GAP));
        }
        // Start the game loop
        if (gameTimer != null) {
            gameTimer.stop();
        }
        gameTimer = new Timer(1000 / 60, this); // 60 FPS
        gameTimer.start();
    }
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        if (!gameOver) {
            // Draw game objects
            bird.draw(g2d);
            for (Pipe pipe : pipes) {
                pipe.draw(g2d);
            }
            // Draw score
            g2d.setColor(Color.WHITE);
            g2d.setFont(new Font("Arial", Font.BOLD, 30));
            g2d.drawString("Score: " + score, 10, 30);
        } else {
            // Draw game over screen
            g2d.setColor(Color.RED);
            g2d.setFont(new Font("Arial", Font.BOLD, 50));
            g2d.drawString("Game Over", WIDTH / 2 - 120, HEIGHT / 2 - 50);
            g2d.setColor(Color.WHITE);
            g2d.setFont(new Font("Arial", Font.BOLD, 30));
            g2d.drawString("Score: " + score, WIDTH / 2 - 60, HEIGHT / 2);
            g2d.drawString("Press SPACE to Restart", WIDTH / 2 - 140, HEIGHT / 2 + 50);
        }
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if (!gameOver) {
            // --- Update Game State ---
            bird.update();
            // Update pipes and check for scoring
            for (int i = pipes.size() - 1; i >= 0; i--) {
                Pipe pipe = pipes.get(i);
                pipe.update();
                // Check for collision
                if (checkCollision(bird, pipe)) {
                    gameOver = true;
                }
                // Score point when bird passes a pipe
                if (pipe.getX() + pipe.getWidth() < bird.getX() && !pipe.isPassed()) {
                    score++;
                    pipe.setPassed(true);
                }
                // Remove pipes that are off-screen and add new ones
                if (pipe.getX() + pipe.getWidth() < 0) {
                    pipes.remove(i);
                    int newPipeX = pipes.get(pipes.size() - 1).getX() + PIPE_SPACING;
                    int topPipeHeight = random.nextInt(HEIGHT - PIPE_GAP - 100) + 50;
                    pipes.add(new Pipe(newPipeX, topPipeHeight, PIPE_GAP));
                }
            }
            // Check for ground/ceiling collision
            if (bird.getY() + bird.getRadius() > HEIGHT || bird.getY() - bird.getRadius() < 0) {
                gameOver = true;
            }
        }
        // Repaint the screen
        repaint();
    }
    private boolean checkCollision(Bird bird, Pipe pipe) {
        // Check if bird is within the horizontal bounds of the pipe
        if (bird.getX() + bird.getRadius() > pipe.getX() && bird.getX() - bird.getRadius() < pipe.getX() + pipe.getWidth()) {
            // Check if bird is within the vertical gap of the pipe
            if (bird.getY() - bird.getRadius() < pipe.getTopHeight() || bird.getY() + bird.getRadius() > pipe.getBottomPipeY()) {
                return true;
            }
        }
        return false;
    }
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SPACE) {
            if (gameOver) {
                resetGame();
            } else {
                bird.jump();
            }
        }
    }
    // --- Unimplemented KeyListener methods ---
    @Override public void keyTyped(KeyEvent e) {}
    @Override public void keyReleased(KeyEvent e) {}
    // --- Main Method to Run the Game ---
    public static void main(String[] args) {
        JFrame frame = new JFrame("Flappy Bird");
        FlappyBird game = new FlappyBird();
        frame.add(game);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null); // Center the window
        frame.setResizable(false);
        frame.setVisible(true);
    }
}

Important Fix for Pipe.java: The FlappyBird.java class calls pipe.isPassed() and pipe.setPassed(). We need to add this functionality to the Pipe class. Add these two methods and a boolean field to Pipe.java:

// Add this field to Pipe.java
private boolean passed;
// Add these methods to Pipe.java
public boolean isPassed() {
    return passed;
}
public void setPassed(boolean passed) {
    this.passed = passed;
}
// And make sure the constructor initializes it:
public Pipe(int x, int topHeight, int gap) {
    this.x = x;
    this.topHeight = topHeight;
    this.gap = gap;
    this.passed = false; // Initialize here
}

Step 5: How to Run the Game

  1. Make sure all three files (FlappyBird.java, Bird.java, Pipe.java) are in the same package/directory.
  2. Run the main method in the FlappyBird.java file.

A window should appear. Press the Spacebar to make the bird jump and avoid the pipes!

Next Steps and Improvements

This is a great starting point. Here are some ways you can enhance the game:

  1. Images: Replace the colored shapes with actual images for the bird, pipes, and background. You would load them using ImageIO.read() and draw them with g.drawImage().
  2. Sound Effects: Add sounds for jumping, scoring, and hitting a pipe using the javax.sound.sampled package.
  3. Menu Screen: Create a main menu screen with a "Start Game" button instead of the game starting immediately.
  4. High Score: Save the highest score to a file so it persists between game sessions.
  5. Physics Tweaks: Adjust the gravity, jumpStrength, and speed values to change the game's feel.
  6. Scrolling Background: Make the background image or color subtly move to create a parallax effect.
分享:
扫描分享到社交APP
上一篇
下一篇