杰瑞科技汇

fly bird的java代码如何实现?

下面我将为你提供一个使用 Java Swing 库编写的、可运行的 Fly Bird 游戏的完整代码,Swing 是 Java 的标准 GUI 工具包,非常适合制作这种简单的2D游戏。

fly bird的java代码如何实现?-图1
(图片来源网络,侵删)

游戏核心机制

  1. 小鸟:受重力影响会不断下落,点击鼠标或按空格键,小鸟会获得一个向上的速度。
  2. 管道:从屏幕右侧以恒定速度向左移动,管道中间有固定的间隙,玩家需要控制小鸟穿过这个间隙。
  3. 碰撞检测:如果小鸟撞到了管道、地面或天花板,游戏结束。
  4. 计分:每成功穿过一组管道,分数加一。

完整 Java 代码

你可以将以下所有代码复制到一个名为 FlyBird.java 的文件中,然后直接编译并运行。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
/**
 * Fly Bird Game (类似 Flappy Bird)
 * 使用 Java Swing 实现
 */
public class FlyBird extends JPanel implements ActionListener, KeyListener {
    // 游戏窗口尺寸
    private final int WIDTH = 400;
    private final int HEIGHT = 600;
    // 游戏状态
    private boolean isGameOver = false;
    private int score = 0;
    // 小鸟属性
    private int birdX = WIDTH / 4;
    private int birdY = HEIGHT / 2;
    private int birdRadius = 10;
    private int birdVelocity = 0;
    private final int gravity = 1;
    private final int jumpStrength = -10;
    // 管道属性
    private final int pipeWidth = 60;
    private final int pipeGap = 150; // 管道间隙
    private final int pipeSpeed = 3;
    private final int pipeSpacing = 200; // 管道之间的水平间距
    private ArrayList<Pipe> pipes;
    private Random random;
    // 计时器
    private Timer gameLoop;
    public FlyBird() {
        // 设置窗口
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.CYAN);
        setFocusable(true);
        addKeyListener(this);
        // 初始化游戏元素
        pipes = new ArrayList<>();
        random = new Random();
        // 创建初始管道
        for (int i = 0; i < 3; i++) {
            addPipe(WIDTH + i * pipeSpacing);
        }
        // 启动游戏循环
        gameLoop = new Timer(20, this); // 每20毫秒 (50 FPS) 更新一次游戏状态
        gameLoop.start();
    }
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 如果游戏结束,显示游戏结束画面
        if (isGameOver) {
            g.setColor(Color.BLACK);
            g.setFont(new Font("Arial", Font.BOLD, 40));
            g.drawString("Game Over", WIDTH / 2 - 100, HEIGHT / 2);
            g.setFont(new Font("Arial", Font.PLAIN, 20));
            g.drawString("Score: " + score, WIDTH / 2 - 40, HEIGHT / 2 + 40);
            g.drawString("Press SPACE to Restart", WIDTH / 2 - 100, HEIGHT / 2 + 80);
        } else {
            // 绘制小鸟
            g.setColor(Color.YELLOW);
            g.fillOval(birdX - birdRadius, birdY - birdRadius, birdRadius * 2, birdRadius * 2);
            // 绘制管道
            for (Pipe pipe : pipes) {
                // 上管道
                g.setColor(Color.GREEN);
                g.fillRect(pipe.x, 0, pipeWidth, pipe.topHeight);
                // 下管道
                g.fillRect(pipe.x, pipe.topHeight + pipeGap, pipeWidth, HEIGHT - pipe.topHeight - pipeGap);
            }
            // 绘制分数
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", Font.BOLD, 30));
            g.drawString("Score: " + score, 10, 40);
        }
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if (!isGameOver) {
            // 1. 更新小鸟位置
            birdVelocity += gravity;
            birdY += birdVelocity;
            // 2. 更新管道位置
            for (int i = 0; i < pipes.size(); i++) {
                Pipe pipe = pipes.get(i);
                pipe.x -= pipeSpeed;
                // 检查是否成功通过管道
                if (!pipe.passed && pipe.x + pipeWidth < birdX) {
                    pipe.passed = true;
                    score++;
                }
                // 移除屏幕外的管道并添加新的
                if (pipe.x + pipeWidth < 0) {
                    pipes.remove(i);
                    addPipe(pipes.get(pipes.size() - 1).x + pipeSpacing);
                    i--; // 因为列表大小改变了,所以需要调整索引
                }
            }
            // 3. 碰撞检测
            checkCollisions();
        }
        // 重绘画面
        repaint();
    }
    private void addPipe(int x) {
        int topHeight = random.nextInt(HEIGHT - pipeGap - 100) + 50; // 随机生成管道高度
        pipes.add(new Pipe(x, topHeight));
    }
    private void checkCollisions() {
        // 检查是否撞到地面或天花板
        if (birdY + birdRadius > HEIGHT || birdY - birdRadius < 0) {
            isGameOver = true;
        }
        // 检查是否撞到管道
        for (Pipe pipe : pipes) {
            // 检查小鸟的x坐标是否在管道的x范围内
            if (birdX + birdRadius > pipe.x && birdX - birdRadius < pipe.x + pipeWidth) {
                // 检查小鸟的y坐标是否在管道间隙之外
                if (birdY - birdRadius < pipe.topHeight || birdY + birdRadius > pipe.topHeight + pipeGap) {
                    isGameOver = true;
                }
            }
        }
    }
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SPACE) {
            if (isGameOver) {
                // 重新开始游戏
                resetGame();
            } else {
                // 小鸟跳跃
                birdVelocity = jumpStrength;
            }
        }
    }
    private void resetGame() {
        isGameOver = false;
        score = 0;
        birdY = HEIGHT / 2;
        birdVelocity = 0;
        pipes.clear();
        for (int i = 0; i < 3; i++) {
            addPipe(WIDTH + i * pipeSpacing);
        }
    }
    // 以下方法为接口实现,此处未使用
    @Override
    public void keyTyped(KeyEvent e) {}
    @Override
    public void keyReleased(KeyEvent e) {}
    public static void main(String[] args) {
        // 在事件调度线程中创建和显示GUI
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Fly Bird");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
            frame.add(new FlyBird());
            frame.pack();
            frame.setLocationRelativeTo(null); // 居中显示
            frame.setVisible(true);
        });
    }
    // 管道内部类
    private class Pipe {
        int x;
        int topHeight;
        boolean passed = false;
        public Pipe(int x, int topHeight) {
            this.x = x;
            this.topHeight = topHeight;
        }
    }
}

如何运行

  1. 保存文件:将上面的代码保存为 FlyBird.java
  2. 打开终端/命令行:导航到你保存文件的目录。
  3. 编译代码:运行 javac FlyBird.java
  4. 运行游戏:运行 java FlyBird

游戏窗口将会弹出,你可以点击鼠标或按空格键来控制小鸟飞行。

代码结构解析

  1. FlyBird:继承自 JPanel,是游戏的主要画布和逻辑中心。
    • main 方法:程序的入口,它创建了一个 JFrame(窗口),并将 FlyBird 实例添加到窗口中,使用 SwingUtilities.invokeLater 确保GUI在正确的线程上创建。
    • 构造函数 FlyBird()
      • 设置窗口大小和背景色。
      • 初始化小鸟、管道和随机数生成器。
      • 创建并启动 TimerTimer 是Swing中实现动画和游戏循环的核心,它会定期触发 actionPerformed 事件。
    • paintComponent(Graphics g) 方法
      • 这是绘制所有游戏元素的地方。
      • 如果游戏结束,它会显示 "Game Over" 和分数,并提供重新开始的提示。
      • 如果游戏正在进行,它会绘制小鸟(黄色圆形)、管道(绿色矩形)和当前分数。
    • actionPerformed(ActionEvent e) 方法
      • 这是游戏的主循环,由 Timer 每隔20毫秒调用一次。
      • 更新状态:更新小鸟的位置(应用重力)和所有管道的位置。
      • 计分:检查小鸟是否成功通过了一组管道。
      • 管道管理:移除已经离开屏幕的管道,并在右侧生成新的管道,保持屏幕上始终有固定数量的管道。
      • 碰撞检测:调用 checkCollisions 方法。
      • 重绘:调用 repaint() 请求系统重新调用 paintComponent,更新画面。
    • checkCollisions() 方法
      • 检查小鸟是否与地面、天花板或任何管道发生碰撞,如果碰撞,则设置 isGameOver = true
    • keyPressed(KeyEvent e) 方法
      • 处理键盘输入,当按下空格键时,如果游戏结束,则调用 resetGame;否则,给小鸟一个向上的速度(模拟跳跃)。
    • resetGame() 方法

      重置所有游戏状态(分数、小鸟位置、管道等),以便可以重新开始游戏。

    • Pipe 内部类

      一个简单的数据类,用于存储单个管道的x坐标、顶部管道的高度以及是否已被小鸟通过(用于计分)。

      fly bird的java代码如何实现?-图2
      (图片来源网络,侵删)

如何扩展和改进

这个版本是一个基础框架,你可以在此基础上添加更多功能,

  1. 开始界面:在游戏开始前显示一个 "Start Game" 的按钮或提示。
  2. 音效:使用 javax.sound 库添加跳跃、得分和游戏结束的音效。
  3. 难度递增:随着分数增加,可以增加管道的移动速度或减小管道间隙。
  4. 背景图片/动画:用图片替换纯色背景,并添加云朵等动画元素。
  5. 更复杂的小鸟动画:根据小鸟的速度和方向绘制不同的姿态。
  6. 最高分记录:使用文件存储和读取最高分。
fly bird的java代码如何实现?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇