1、演示视频
基于Java Swing的打砖块小游戏
2、项目截图
设计说明
3.1 整体架构设计
项目采用分层设计+面向对象封装的架构,主要分为以下几个部分:
- 界面层(UI层):由<代码开始>BreakoutGame<代码结束>类中的<代码开始>initUI()<代码结束>方法实现,负责创建游戏窗口、布局管理、组件初始化、事件绑定等。
- 游戏逻辑层:由<代码开始>updateGame()<代码结束>、<代码开始>checkCollisions()<代码结束>、<代码开始>checkGameStatus()<代码结束>等方法实现,负责处理游戏元素的运动、碰撞检测、状态判断等核心逻辑。
- 数据模型层:由<代码开始>Paddle<代码结束>(挡板)、<代码开始>Ball<代码结束>(小球)、<代码开始>Brick<代码结束>(砖块)三个内部类实现,封装了游戏元素的属性和行为。
- 渲染层:由<代码开始>GamePanel<代码结束>内部类的<代码开始>paintComponent()<代码结束>方法实现,负责绘制游戏元素和状态提示。
3.2 类结构设计
| 类名 | 类型 | 作用 |
|---|---|---|
| BreakoutGame | 主类(继承JFrame) | 游戏入口,负责初始化界面、管理游戏状态、处理核心逻辑 |
| GamePanel | 内部类(继承JPanel) | 游戏显示区的面板,负责绘制游戏元素和胜负提示 |
| Paddle | 内部类 | 封装挡板的属性(位置、尺寸、速度)和行为(移动) |
| Ball | 内部类 | 封装小球的属性(位置、尺寸、速度)和行为(移动、反弹、加速) |
| Brick | 内部类 | 封装砖块的属性(位置、尺寸)和状态(是否被消除) |
3.3 布局设计
游戏窗口采用<代码开始>BorderLayout<代码结束>布局,分为两个区域:
- CENTER区域:游戏显示区(<代码开始>GamePanel<代码结束>),尺寸为800×600像素,负责绘制游戏元素。
- SOUTH区域:底部信息区(<代码开始>JPanel<代码结束>),高度为150像素,包含:
- 提示文本域(<代码开始>JTextArea<代码结束>):支持自动换行,显示游戏规则、状态提示
- 重新开始按钮(<代码开始>JButton<代码结束>):游戏胜利/失败时显示,点击后重置游戏
3.4 核心数据设计
项目中定义了大量常量来管理游戏的固定参数,便于统一修改和维护,主要常量分类如下:
- 窗口常量:游戏显示区的宽度、高度,底部信息区的高度
- 元素常量:挡板、小球、砖块的尺寸、速度、数量、间距
- 游戏常量:刷新频率、小球最大速度、速度增量
- 字体常量:统一管理界面中使用的字体样式和大小,解决中文乱码问题
四、算法说明
4.1 小球运动算法
小球的运动采用匀速直线运动模型,通过速度变量控制移动方向和距离,具体逻辑:
- 初始化:小球的初始速度由<代码开始>BALL_INIT_X_SPEED<代码结束>(X轴)和<代码开始>BALL_INIT_Y_SPEED<代码结束>(Y轴)定义,正数表示向右/向下,负数表示向左/向上。
- 移动:每次刷新时,小球的X坐标增加X轴速度,Y坐标增加Y轴速度(<代码开始>ball.move()<代码结束>方法)。
- 反弹:小球碰到边界、挡板、砖块后,反转对应轴的速度(如碰到左右边界反转X轴速度,碰到上下边界/挡板/砖块反转Y轴速度)。
- 加速:每消除1/3的砖块,小球的X轴和Y轴速度绝对值增加(<代码开始>increaseBallSpeed()<代码结束>方法),但不超过最大速度限制。
4.2 碰撞检测算法
项目采用矩形相交检测法(<代码开始>java.awt.Rectangle<代码结束>的<代码开始>intersects()<代码结束>方法)来检测碰撞,核心逻辑如下:
4.2.1 小球与边界的碰撞检测
// 小球与左右边界碰撞 if (ball.getX() <= 0 || ball.getX() + ball.getWidth() >= WIDTH) { ball.reverseXDirection(); // 反转X轴速度 ball.setX(Math.max(0, Math.min(ball.getX(), WIDTH - ball.getWidth()))); // 限制位置 } // 小球与上边界碰撞 if (ball.getY() <= 0) { ball.reverseYDirection(); // 反转Y轴速度 ball.setY(Math.max(0, ball.getY())); // 限制位置 } // 小球与下边界碰撞(游戏失败) if (ball.getY() + ball.getHeight() >= HEIGHT) { isGameOver = true; // 标记游戏失败 }4.2.2 小球与挡板的碰撞检测
检测小球的边界矩形与挡板的边界矩形是否相交,若相交则处理反弹逻辑,并根据小球与挡板中心的偏移量调整小球的X轴速度,实现角度反弹效果:
if (ballBounds.intersects(paddleBounds)) { if (ball.getYSpeed() > 0 && ball.getY() + ball.getHeight() <= paddleBounds.getY() + paddleBounds.getHeight() / 2) { ball.reverseYDirection(); // 反转Y轴速度 // 计算偏移量,调整X轴速度 int ballCenter = ball.getX() + ball.getWidth() / 2; int paddleCenter = paddle.getX() + paddleBounds.getWidth() / 2; int offset = ballCenter - paddleCenter; int newXSpeed = Math.max(-BALL_MAX_SPEED, Math.min(offset / 5, BALL_MAX_SPEED)); ball.setxSpeed(newXSpeed != 0 ? newXSpeed : BALL_INIT_X_SPEED); } ball.setY(paddleBounds.getY() - ball.getHeight() - 1); // 防止小球陷入挡板 }4.2.3 小球与砖块的碰撞检测
遍历砖块列表,检测小球与每个未被消除的砖块的边界矩形是否相交,若相交则标记砖块为已消除、移除砖块、反转小球Y轴速度,并触发小球加速逻辑:
Iterator brickIterator = bricks.iterator(); while (brickIterator.hasNext()) { Brick brick = brickIterator.next(); if (!brick.isBroken() && ballBounds.intersects(brick.getBounds())) { brick.setBroken(true); // 标记砖块已消除 brickIterator.remove(); // 移除砖块 ball.reverseYDirection(); // 反转Y轴速度 increaseBallSpeed(); // 小球加速 break; // 一次只处理一个砖块的碰撞 } }4.3 游戏状态判断算法
游戏状态分为未开始、游戏中、胜利、失败四种,通过布尔变量标记,判断逻辑如下:
- 未开始:
isGameStart = false,初始状态,按下空格键后变为true。 - 游戏中:
isGameStart = true且isGameOver = false且isGameWin = false。 - 失败:
isGameOver = true,小球碰到下边界时触发。 - 胜利:
isGameWin = true,砖块列表为空(所有砖块被消除)时触发。
五、测试说明
5.1 测试环境
- 硬件环境:Intel Core i5及以上处理器,4GB及以上内存
- 软件环境:Windows 10/11、Java 8/11/17、IntelliJ IDEA 2023
5.2 测试用例
| 测试用例ID | 测试内容 | 测试步骤 | 预期结果 | 测试结果 |
|---|---|---|---|---|
| TC001 | 游戏启动 | 运行主类,观察窗口是否正常显示 | 窗口正常显示,底部信息区显示游戏规则和启动提示 | 通过 |
| TC002 | 启动游戏 | 按下空格键,观察小球是否开始运动 | 小球开始按照初始速度运动,底部信息区显示“游戏中”提示 | 通过 |
| TC003 | 挡板控制 | 按下左/右方向键,观察挡板是否移动 | 挡板随方向键左右移动,且不会超出窗口边界 | 通过 |
| TC004 | 小球边界反弹 | 观察小球碰到左右、上边界时的行为 | 小球碰到边界后反弹,方向正确 | 通过 |
| TC005 | 小球挡板碰撞 | 控制挡板接住小球,观察碰撞后的行为 | 小球反弹,且根据碰撞位置调整X轴速度 | 通过 |
| TC006 | 砖块消除 | 小球碰到砖块,观察砖块是否消失 | 砖块被消除,从界面中消失 | 通过 |
| TC007 | 小球加速 | 消除1/3、2/3砖块时,观察小球速度 | 小球速度依次增加,不超过最大速度 | 通过 |
| TC008 | 游戏失败 | 让小球碰到下边界,观察游戏状态 | 游戏停止,显示失败提示,出现重新开始按钮 | 通过 |
| TC009 | 游戏胜利 | 消除所有砖块,观察游戏状态 | 游戏停止,显示胜利提示,出现重新开始按钮 | 通过 |
| TC010 | 重新开始游戏 | 点击重新开始按钮或按空格键,观察游戏状态 | 游戏重置为初始状态,可重新启动 | 通过 |
5.3 测试总结
所有测试用例均通过,游戏的核心功能(界面展示、用户交互、碰撞检测、状态管理)均能正常工作,无明显bug。游戏运行流畅,界面响应及时,用户体验良好。
六、关键代码
6.1 游戏主类初始化代码
主类的构造方法,负责初始化界面、游戏元素和启动游戏循环:
/** * 构造方法:初始化游戏窗口和核心组件 * 执行流程:初始化界面 -> 初始化游戏元素 -> 启动游戏定时器 */ public BreakoutGame() { // 窗口尺寸校验(防止传入无效的尺寸值) if (WIDTH <= 0 || HEIGHT <= 0) { throw new IllegalArgumentException("窗口尺寸不能为负数或零"); } // 初始化游戏界面组件 initUI(); // 初始化游戏核心元素(挡板、小球、砖块) initGame(); // 启动游戏定时器(开始游戏循环) startGameLoop(); }6.2 碰撞检测核心代码
处理小球与挡板、砖块的碰撞逻辑,是游戏的核心算法之一:
/** * 碰撞检测 * 功能:检测小球与挡板、砖块的碰撞,并处理碰撞后的逻辑(反弹、消除砖块、加速小球) */ private void checkCollisions() { // 获取小球的边界矩形(用于碰撞检测) Rectangle ballBounds = ball.getBounds(); // 获取挡板的边界矩形(用于碰撞检测) Rectangle paddleBounds = paddle.getBounds(); // ========== 小球与挡板碰撞检测与处理 ========== if (ballBounds.intersects(paddleBounds)) { // 仅处理小球向下运动时的碰撞(避免多次反弹) if (ball.getYSpeed() > 0 && ball.getY() + ball.getHeight() <= paddleBounds.getY() + paddleBounds.getHeight() / 2) { // 反转Y轴速度(小球向上反弹) ball.reverseYDirection(); // 计算小球与挡板中心的偏移量(用于调整小球X轴速度,实现角度反弹) int ballCenter = ball.getX() + ball.getWidth() / 2; int paddleCenter = paddle.getX() + paddleBounds.getWidth() / 2; int offset = ballCenter - paddleCenter; // 计算新的X轴速度(限制在最大速度范围内) int newXSpeed = Math.max(-BALL_MAX_SPEED, Math.min(offset / 5, BALL_MAX_SPEED)); // 设置小球X轴速度(如果速度为0,使用初始速度,避免小球垂直运动) ball.setxSpeed(newXSpeed != 0 ? newXSpeed : BALL_INIT_X_SPEED); } // 调整小球位置,防止小球陷入挡板内部 ball.setY(paddleBounds.getY() - ball.getHeight() - 1); } // ========== 小球与砖块碰撞检测与处理 ========== // 使用迭代器遍历砖块列表(支持遍历过程中删除元素) Iterator brickIterator = bricks.iterator(); while (brickIterator.hasNext()) { Brick brick = brickIterator.next(); // 仅检测未被消除的砖块与小球的碰撞 if (!brick.isBroken() && ballBounds.intersects(brick.getBounds())) { // 标记砖块为已消除 brick.setBroken(true); // 从列表中移除已消除的砖块 brickIterator.remove(); // 反转小球Y轴速度(反弹) ball.reverseYDirection(); // 增加小球速度(每消除1/3砖块时加速一次) increaseBallSpeed(); // 跳出循环(一次只处理一个砖块的碰撞,避免多次碰撞导致速度异常) break; } } }6.3 游戏面板绘制代码
负责绘制游戏元素和胜负提示,是界面渲染的核心代码:
/** * 游戏面板内部类 * 功能:负责绘制游戏元素(挡板、小球、砖块)和胜负提示 */ private class GamePanel extends JPanel { /** * 重绘方法:绘制游戏界面 * @param g 绘图上下文对象(用于绘制图形) */ @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 调用父类方法,绘制背景 // 转换为2D绘图上下文(支持更丰富的绘图功能) Graphics2D g2d = (Graphics2D) g; // 开启抗锯齿(让绘制的图形更平滑) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // ========== 仅在游戏已开始时,绘制游戏元素 ========== if (isGameStart) { // 绘制挡板:蓝色矩形 g2d.setColor(Color.BLUE); g2d.fillRect(paddle.getX(), paddle.getY(), paddle.getWidth(), paddle.getHeight()); // 绘制小球:红色圆形(通过填充椭圆实现) g2d.setColor(Color.RED); g2d.fillOval(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight()); // 绘制砖块:遍历砖块列表,绘制未被消除的砖块(绿色矩形,黑色边框) for (Brick brick : bricks) { if (!brick.isBroken()) { g2d.setColor(Color.GREEN); g2d.fillRect(brick.getX(), brick.getY(), brick.getWidth(), brick.getHeight()); g2d.setColor(Color.BLACK); g2d.drawRect(brick.getX(), brick.getY(), brick.getWidth(), brick.getHeight()); } } // ========== 绘制胜负提示(视觉强化) ========== g2d.setFont(FONT_BOLD_LARGE); // 设置提示字体 if (isGameOver) { // 游戏失败:红色文字显示“游戏结束!”(水平居中) g2d.setColor(Color.RED); g2d.drawString("游戏结束!", WIDTH / 2 - 100, HEIGHT / 2); } else if (isGameWin) { // 游戏胜利:绿色文字显示“恭喜胜利!”(水平居中) g2d.setColor(Color.GREEN); g2d.drawString("恭喜胜利!", WIDTH / 2 - 100, HEIGHT / 2); } } // 游戏未开始时,游戏面板为空(所有提示在底部) } /** * 重写首选尺寸方法:确保游戏面板占满指定的游戏区域 * @return 游戏面板的首选尺寸(宽度WIDTH,高度HEIGHT) */ @Override public Dimension getPreferredSize() { return new Dimension(WIDTH, HEIGHT); } }6.4 小球加速代码
实现小球的加速逻辑,提升游戏难度:
/** * 增加小球速度 * 功能:每消除1/3的砖块,小球速度增加一次(限制在最大速度范围内) */ private void increaseBallSpeed() { // 获取当前剩余砖块数量 int currentBrickCount = bricks.size(); // 计算已消除的砖块数量是否达到1/3的阈值(brickCount / 3为每次加速的阈值) if (brickCount / 3 > 0 && (brickCount - currentBrickCount) % (brickCount / 3) == 0 && ball.getSpeed() < BALL_MAX_SPEED) { // 增加小球速度(X轴和Y轴速度都增加) ball.increaseSpeed(BALL_SPEED_INCREMENT); } }七、扩展建议
为了丰富游戏功能和提升用户体验,可对项目进行以下扩展:
- 添加计分系统:记录玩家消除砖块的数量,显示得分
- 添加关卡系统:设置不同的砖块布局和小球速度,实现多关卡游戏
- 添加音效:碰撞、消除砖块、胜利/失败时播放音效
- 添加皮肤系统:支持更换挡板、小球、砖块的颜色和样式
- 添加暂停功能:支持暂停和继续游戏
- 优化碰撞检测:采用更精确的像素碰撞检测,替代矩形相交检测