在Java中如何开发小地鼠小游戏

来源:IPIPP.com作者:头衔:全栈工程师
导读:本期聚焦于小伙伴创作的《在Java中如何开发小地鼠小游戏》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《在Java中如何开发小地鼠小游戏》有用,将其分享出去将是对创作者最好的鼓励。

一、开发前准备

开发Java打地鼠小游戏不需要复杂的第三方依赖,只要本地安装了JDK 8及以上版本即可,我们主要使用Java自带的Swing图形界面库完成界面开发,用AWT包处理事件逻辑。如果你用的是IDEA、Eclipse这类开发工具,直接新建一个普通的Java项目就能开始,不需要额外导入外部jar包。

首先要明确打地鼠游戏的核心需求:界面上有多个地鼠洞,地鼠会随机从某个洞里冒出,玩家点击冒出的地鼠就能得分,游戏有固定时长,时间结束后显示最终得分。基于这个需求,我们可以把开发拆成几个模块:界面绘制模块、地鼠状态控制模块、事件监听模块、得分计时模块。

在Java中如何开发小地鼠小游戏

二、基础界面搭建

界面部分我们用JFrame作为主窗口,用JPanel作为游戏画布,地鼠洞和地鼠都用图形绘制的方式实现,不需要引入外部图片资源,方便新手理解。首先我们先定义一些基础常量,比如窗口大小、地鼠洞的数量和位置、地鼠的大小等。

import javax.swing.*;
import java.awt.*;

// 打地鼠游戏主类
public class WhackAMoleGame extends JFrame {
    // 游戏窗口宽度
    private static final int WINDOW_WIDTH = 600;
    // 游戏窗口高度
    private static final int WINDOW_HEIGHT = 700;
    // 地鼠洞列数
    private static final int HOLE_COLS = 3;
    // 地鼠洞行数
    private static final int HOLE_ROWS = 3;
    // 单个地鼠洞的边长
    private static final int HOLE_SIZE = 120;
    // 地鼠洞之间的间距
    private static final int HOLE_GAP = 20;
    // 地鼠大小(比洞小一圈)
    private static final int MOLE_SIZE = 80;
    // 游戏总时长(秒)
    private static final int GAME_DURATION = 30;

    // 游戏画布面板
    private GamePanel gamePanel;
    // 得分标签
    private JLabel scoreLabel;
    // 计时标签
    private JLabel timeLabel;
    // 当前得分
    private int score = 0;
    // 剩余时间
    private int remainTime = GAME_DURATION;
    // 计时器,控制地鼠出现和游戏计时
    private Timer gameTimer;
    // 地鼠出现的洞索引,-1表示没有地鼠
    private int activeMoleIndex = -1;

    public WhackAMoleGame() {
        initWindow();
        initComponents();
        startGame();
    }

    // 初始化窗口属性
    private void initWindow() {
        setTitle("Java打地鼠小游戏");
        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 窗口居中显示
        setResizable(false); // 禁止调整窗口大小
    }

    // 初始化界面组件
    private void initComponents() {
        // 使用边框布局
        setLayout(new BorderLayout());

        // 顶部信息面板,显示得分和剩余时间
        JPanel infoPanel = new JPanel(new GridLayout(1, 2));
        scoreLabel = new JLabel("得分:0", SwingConstants.CENTER);
        scoreLabel.setFont(new Font("微软雅黑", Font.BOLD, 20));
        timeLabel = new JLabel("剩余时间:" + GAME_DURATION + "秒", SwingConstants.CENTER);
        timeLabel.setFont(new Font("微软雅黑", Font.BOLD, 20));
        infoPanel.add(scoreLabel);
        infoPanel.add(timeLabel);
        add(infoPanel, BorderLayout.NORTH);

        // 游戏画布面板
        gamePanel = new GamePanel();
        gamePanel.setBackground(new Color(220, 220, 220));
        add(gamePanel, BorderLayout.CENTER);
    }

    // 其他代码后续补充
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new WhackAMoleGame().setVisible(true);
        });
    }
}

上面的代码定义了游戏的基础常量,初始化了主窗口和顶部的得分、时间显示面板,其中GamePanel是我们自定义的游戏画布类,接下来我们需要实现这个类,完成地鼠洞和地鼠的绘制。

游戏画布类实现

游戏画布需要继承JPanel,重写paintComponent方法完成图形绘制,同时需要添加鼠标点击事件监听,判断玩家是否点击到了地鼠。

// 游戏画布类,负责绘制界面和处理鼠标点击
class GamePanel extends JPanel {
    private WhackAMoleGame gameFrame;

    public GamePanel() {
        // 添加鼠标点击事件监听
        addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mouseClicked(java.awt.event.MouseEvent e) {
                handleMouseClick(e.getX(), e.getY());
            }
        });
    }

    // 绘制界面
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 计算地鼠洞的起始绘制位置,让整体居中
        int startX = (getWidth() - (WhackAMoleGame.HOLE_COLS * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP) - WhackAMoleGame.HOLE_GAP)) / 2;
        int startY = (getHeight() - (WhackAMoleGame.HOLE_ROWS * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP) - WhackAMoleGame.HOLE_GAP)) / 2;

        // 绘制所有地鼠洞
        for (int row = 0; row < WhackAMoleGame.HOLE_ROWS; row++) {
            for (int col = 0; col < WhackAMoleGame.HOLE_COLS; col++) {
                int holeX = startX + col * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP);
                int holeY = startY + row * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP);
                // 绘制地鼠洞(灰色圆形)
                g.setColor(new Color(100, 100, 100));
                g.fillOval(holeX, holeY, WhackAMoleGame.HOLE_SIZE, WhackAMoleGame.HOLE_SIZE);
                // 绘制洞的边缘(深灰色)
                g.setColor(new Color(60, 60, 60));
                g.drawOval(holeX, holeY, WhackAMoleGame.HOLE_SIZE, WhackAMoleGame.HOLE_SIZE);

                // 计算当前洞的索引
                int index = row * WhackAMoleGame.HOLE_COLS + col;
                // 如果当前洞有活跃地鼠,绘制地鼠
                if (index == gameFrame.activeMoleIndex) {
                    int moleX = holeX + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;
                    int moleY = holeY + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;
                    // 绘制地鼠(棕色圆形)
                    g.setColor(new Color(139, 69, 19));
                    g.fillOval(moleX, moleY, WhackAMoleGame.MOLE_SIZE, WhackAMoleGame.MOLE_SIZE);
                    // 绘制地鼠眼睛
                    g.setColor(Color.WHITE);
                    g.fillOval(moleX + 20, moleY + 20, 15, 15);
                    g.fillOval(moleX + WhackAMoleGame.MOLE_SIZE - 35, moleY + 20, 15, 15);
                    g.setColor(Color.BLACK);
                    g.fillOval(moleX + 24, moleY + 24, 7, 7);
                    g.fillOval(moleX + WhackAMoleGame.MOLE_SIZE - 31, moleY + 24, 7, 7);
                }
            }
        }
    }

    // 处理鼠标点击事件
    private void handleMouseClick(int clickX, int clickY) {
        // 计算地鼠洞的起始位置
        int startX = (getWidth() - (WhackAMoleGame.HOLE_COLS * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP) - WhackAMoleGame.HOLE_GAP)) / 2;
        int startY = (getHeight() - (WhackAMoleGame.HOLE_ROWS * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP) - WhackAMoleGame.HOLE_GAP)) / 2;

        // 遍历所有地鼠洞,判断点击位置是否在某个洞的地鼠范围内
        for (int row = 0; row < WhackAMoleGame.HOLE_ROWS; row++) {
            for (int col = 0; col < WhackAMoleGame.HOLE_COLS; col++) {
                int holeX = startX + col * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP);
                int holeY = startY + row * (WhackAMoleGame.HOLE_SIZE + WhackAMoleGame.HOLE_GAP);
                int moleX = holeX + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;
                int moleY = holeY + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;

                // 判断点击位置是否在当前地鼠范围内
                if (clickX >= moleX && clickX <= moleX + WhackAMoleGame.MOLE_SIZE &&
                    clickY >= moleY && clickY <= moleY + WhackAMoleGame.MOLE_SIZE) {
                    int clickedIndex = row * WhackAMoleGame.HOLE_COLS + col;
                    // 如果点击的是活跃地鼠,得分并隐藏地鼠
                    if (clickedIndex == gameFrame.activeMoleIndex) {
                        gameFrame.increaseScore();
                        gameFrame.hideMole();
                    }
                    return;
                }
            }
        }
    }

    // 设置关联的 gameFrame,方便获取游戏状态
    public void setGameFrame(WhackAMoleGame gameFrame) {
        this.gameFrame = gameFrame;
    }
}

三、核心游戏逻辑实现

界面绘制完成后,我们需要实现地鼠随机出现、游戏计时、得分统计这些核心逻辑。这里我们用Swing的Timer类做定时调度,每隔一段时间刷新一次地鼠状态,同时更新剩余时间。

地鼠状态控制

地鼠的出现和隐藏需要两个定时器协同工作:一个控制地鼠出现的间隔,一个控制单只地鼠显示的时长。为了避免复杂度,我们可以用一个定时器,每次触发时先判断当前是否有活跃地鼠,如果有就隐藏,没有就随机选一个洞显示地鼠。

// 补充WhackAMoleGame类中的方法
// 开始游戏
private void startGame() {
    score = 0;
    remainTime = GAME_DURATION;
    updateScoreLabel();
    updateTimeLabel();
    activeMoleIndex = -1;

    // 将gameFrame关联到gamePanel
    gamePanel.setGameFrame(this);

    // 创建游戏定时器,每1000毫秒(1秒)触发一次
    gameTimer = new Timer(1000, e -> {
        // 更新剩余时间
        remainTime--;
        updateTimeLabel();

        // 如果时间到,结束游戏
        if (remainTime <= 0) {
            endGame();
            return;
        }

        // 控制地鼠出现逻辑:如果当前没有活跃地鼠,随机选一个显示
        if (activeMoleIndex == -1) {
            // 生成0到HOLE_COLS*HOLE_ROWS-1的随机数,作为地鼠出现的洞索引
            activeMoleIndex = (int) (Math.random() * HOLE_COLS * HOLE_ROWS);
            gamePanel.repaint(); // 重绘画布,显示地鼠
            // 地鼠显示1秒后自动隐藏
            Timer moleTimer = new Timer(1000, moleEvent -> {
                hideMole();
            });
            moleTimer.setRepeats(false); // 只执行一次
            moleTimer.start();
        }
    });
    gameTimer.start();
}

// 隐藏地鼠
public void hideMole() {
    activeMoleIndex = -1;
    gamePanel.repaint();
}

// 增加得分
public void increaseScore() {
    score++;
    updateScoreLabel();
}

// 更新得分标签
private void updateScoreLabel() {
    scoreLabel.setText("得分:" + score);
}

// 更新时间标签
private void updateTimeLabel() {
    timeLabel.setText("剩余时间:" + remainTime + "秒");
}

// 结束游戏
private void endGame() {
    gameTimer.stop();
    JOptionPane.showMessageDialog(this, "游戏结束!你的最终得分是:" + score, "提示", JOptionPane.INFORMATION_MESSAGE);
    // 可选:结束后重置游戏
    int choice = JOptionPane.showConfirmDialog(this, "是否重新开始游戏?", "提示", JOptionPane.YES_NO_OPTION);
    if (choice == JOptionPane.YES_OPTION) {
        startGame();
    } else {
        System.exit(0);
    }
}

到这里,一个简单的打地鼠小游戏就已经可以运行了。启动main方法后,窗口会弹出,顶部显示得分和剩余时间,每隔一段时间会随机有一个地鼠从洞里冒出来,点击地鼠就能得分,30秒后游戏结束,弹出最终得分提示。

在Java中如何开发小地鼠小游戏

四、功能扩展优化

基础版本的游戏功能比较单一,我们可以做一些简单的扩展,让游戏体验更好。比如调整地鼠出现的频率、增加不同分值的地鼠、添加音效、增加难度梯度等。

1. 调整地鼠出现时长

现在地鼠固定显示1秒,我们可以把显示时长改成随机值,比如500毫秒到1500毫秒之间,增加游戏的随机性:

// 修改启动地鼠定时器的部分,将固定的1000毫秒改成随机值
if (activeMoleIndex == -1) {
    activeMoleIndex = (int) (Math.random() * HOLE_COLS * HOLE_ROWS);
    gamePanel.repaint();
    // 随机生成500-1500毫秒的显示时长
    int moleShowTime = 500 + (int) (Math.random() * 1000);
    Timer moleTimer = new Timer(moleShowTime, moleEvent -> {
        hideMole();
    });
    moleTimer.setRepeats(false);
    moleTimer.start();
}

2. 增加难度梯度

可以让游戏随着时间推移难度逐渐增加,比如剩余时间越少,地鼠出现的频率越高,显示的时间越短:

// 修改定时器中的地鼠出现逻辑,根据剩余时间调整出现概率
gameTimer = new Timer(1000, e -> {
    remainTime--;
    updateTimeLabel();

    if (remainTime <= 0) {
        endGame();
        return;
    }

    if (activeMoleIndex == -1) {
        // 剩余时间越少,地鼠出现概率越高,最高80%
        double appearRate = 0.3 + (double)(GAME_DURATION - remainTime) / GAME_DURATION * 0.5;
        if (Math.random() < appearRate) {
            activeMoleIndex = (int) (Math.random() * HOLE_COLS * HOLE_ROWS);
            gamePanel.repaint();
            // 剩余时间越少,地鼠显示时间越短,最短300毫秒
            int moleShowTime = 1500 - (int)((double)(GAME_DURATION - remainTime) / GAME_DURATION * 1200);
            moleShowTime = Math.max(moleShowTime, 300);
            Timer moleTimer = new Timer(moleShowTime, moleEvent -> {
                hideMole();
            });
            moleTimer.setRepeats(false);
            moleTimer.start();
        }
    }
});

3. 添加特殊地鼠

可以增加一种金色地鼠,点击后得5分,但是出现概率很低,显示时间也更短:

// 定义特殊地鼠的标识,0普通地鼠,1金色地鼠
private int moleType = 0;
// 普通地鼠得分
private static final int NORMAL_SCORE = 1;
// 金色地鼠得分
private static final int GOLDEN_SCORE = 5;

// 修改地鼠出现逻辑,10%概率出现金色地鼠
if (activeMoleIndex == -1) {
    double appearRate = 0.3 + (double)(GAME_DURATION - remainTime) / GAME_DURATION * 0.5;
    if (Math.random() < appearRate) {
        activeMoleIndex = (int) (Math.random() * HOLE_COLS * HOLE_ROWS);
        // 10%概率生成金色地鼠
        if (Math.random() < 0.1) {
            moleType = 1;
        } else {
            moleType = 0;
        }
        gamePanel.repaint();
        int moleShowTime = 1500 - (int)((double)(GAME_DURATION - remainTime) / GAME_DURATION * 1200);
        moleShowTime = Math.max(moleShowTime, 300);
        // 金色地鼠显示时间更短,再减200毫秒
        if (moleType == 1) {
            moleShowTime = Math.max(moleShowTime - 200, 100);
        }
        Timer moleTimer = new Timer(moleShowTime, moleEvent -> {
            hideMole();
        });
        moleTimer.setRepeats(false);
        moleTimer.start();
    }
}

// 修改得分逻辑,根据地鼠类型加分
public void increaseScore() {
    if (moleType == 1) {
        score += GOLDEN_SCORE;
    } else {
        score += NORMAL_SCORE;
    }
    updateScoreLabel();
}

// 修改绘制逻辑,金色地鼠用黄色绘制
if (index == gameFrame.activeMoleIndex) {
    int moleX = holeX + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;
    int moleY = holeY + (WhackAMoleGame.HOLE_SIZE - WhackAMoleGame.MOLE_SIZE) / 2;
    // 根据类型选颜色,普通棕色,金色黄色
    if (gameFrame.moleType == 1) {
        g.setColor(new Color(255, 215, 0));
    } else {
        g.setColor(new Color(139, 69, 19));
    }
    g.fillOval(moleX, moleY, WhackAMoleGame.MOLE_SIZE, WhackAMoleGame.MOLE_SIZE);
    // 绘制眼睛等其他逻辑不变
}

五、开发注意事项

在开发过程中有几个需要注意的点,避免踩坑:

  • Swing的所有界面操作都需要在事件调度线程(EDT)中执行,所以我们main方法里用了SwingUtilities.invokeLater,避免界面卡顿或者异常。
  • 定时器的触发间隔不要太短,否则会频繁触发重绘,导致界面卡顿,一般游戏逻辑更新的间隔在100-1000毫秒之间比较合适。
  • 鼠标点击的判断要准确,因为我们是用圆形绘制地鼠,严格来说应该判断点击位置是否在圆形范围内,上面的代码为了简化用了矩形判断,你可以优化成圆形碰撞检测,更准确。
  • 如果在游戏里添加音效,建议使用单独的线程播放,不要阻塞EDT,否则点击地鼠的时候会出现卡顿。

通过这个小游戏的开发,你可以熟悉Java Swing的基本用法、事件监听机制、定时器的使用,以及简单的游戏逻辑设计思路。后续你还可以继续扩展,比如添加开始暂停按钮、最高分记录、更多的地鼠类型、不同的游戏场景等,逐步提升复杂度,也能更深入理解Java编程的相关知识点。

Java游戏开发打地鼠实现Java_Swing事件监听游戏逻辑设计修改时间:2026-05-24 20:18:24

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。