在之前的文章中,我对一颗小球的畅想 v1.0 版本进行了实现,详细点击这里:一颗小球的畅想 v1.0,在 v1.0 版本中,实现了弹球游戏的基本功能需求,在文章的末尾,我也留了些坑,打算有时间慢慢填,本章将继续对 v1.0 版本功能上进行增强,这个版本暂且定为 v1.1。
1、游戏运行效果图
首先上图,查看运行效果。
程序模块划分如下
- Constant 类:用于存放游戏中的常量数据
- Ball 类:球类
- GameView 类:游戏视图类
- Racket 类:球拍类
- Rule 类:游戏规则类
- GameApplication 类:游戏启动类
2、历史版本
3、版本更新
- 通过空格键,实现游戏的暂停和继续
- 小球的速度和方向实现随机
- 弹球游戏实现分数统计功能
4、游戏的暂停和继续
为了通过点击空格键,实现游戏的开始和暂停,这里需要对键盘点击事件的处理进行改造。我将键盘点击事件处理从方法中提取出来,成为 GameApplication 的一个内部类,继承 KeyAdapter 类,并增加了对空格键点击的监听。
class GameKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) { // 按左键,球拍左移动
racketTop.moveLeft(moveLength);
racketBottom.moveLeft(moveLength);
} else if (keyCode == KeyEvent.VK_RIGHT) { // 按右键,球拍右移动
racketTop.moveRight(moveLength);
racketBottom.moveRight(moveLength);
} else if (keyCode == KeyEvent.VK_SPACE) { // 按空格键,游戏继续和暂停
gameView.runStatus();
}
}
}
点击空格键时,会去调用 GameView 类的 runStatus 方法来改变游戏的运行状态,游戏通过一个定时器来实现游戏的运行, runStatus 方法中实现了定时器的开启和关闭操作。
/**
* 游戏的开始和暂停
*/
public void runStatus() {
if (timer.isRunning()) {
timer.stop();
} else {
timer.start();
}
}
5、小球的速度和方向随机
在上个版本中,小球的速度是固定的,因此每次运行时小球的运行路径是一样的,为了增加随机性,这里需要对小球的速度进行改造。
这里需要确保小球开始时是向下运动的,因此,speedY 的值需要大于 0,同时为了让小球不横向移动,speedY 的绝对值也需要比 speedX 大。
// 球的速度
public static final int speedX = new Random().nextInt(5) + 5;
public static final int speedY = new Random().nextInt(5) + 10;
6、弹球游戏实现分数统计功能
游戏右边多出来一块区域,用于展示玩家的得分情况,这里仅需对桌面的宽度进行调整即可 。这里还需要绘制分割线、得分栏和分数,代码如下:
// 绘制直线
g.setColor(Color.LIGHT_GRAY);
g.fillRect(452, 0, 2, 600);
// 绘制分数板
g.setColor(Color.LIGHT_GRAY);
g.fillRect(475, 130, 100,100);
// 绘制分数
g.setColor(Color.black);
g.setFont(new Font("隶书", Font.BOLD, 30));
g.drawString(Integer.toString(score), 515, 190);
游戏得分使用一个全局 score 变量来进行保存,在进行绘制时使用,得分规则是只要木板接住小球,即可加 1 分,这里需要在规则类 Rule 中编写 scoreAdd 方法,来判断是否需要加分。
private int preSpeed = Constant.speedY;
/**
* 是否加分
* @param ball 球类
*/
public boolean scoreAdd(Ball ball) {
if (preSpeed != ball.getSpeedY()) {
this.preSpeed = ball.getSpeedY();
return true;
}
return false;
}
判断加分的方式很简单,只要 speedY 的速度发生了改变,就说明被木板击中,可以得分。
得分方法需要在定时器中调用。
public GameView(Ball ball, Racket racketTop, Racket racketBotton) {
// 设置桌面
this.setPreferredSize(new Dimension(TABLE_WIDTH + Constant.TABLE_WIDTH_EXTEND, TABLE_HEIGHT));
this.rule = new Rule();
this.ball = ball;
this.racketTop = racketTop;
this.racketBottom = racketBotton;
// 定时刷新任务
timer = new Timer(100, event -> {
// 小球移动
ball.moveBall(racketBotton.getRacketX());
// 统计分数
if (rule.scoreAdd(ball)) {
score++;
}
// 绘制界面
this.repaint();
});
timer.start();
}
7、总结
至此,我们就实现了游戏的暂停和继续,小球速度和方向随机,小球实现分数统计三个功能,但在功能上仍有许多不足之处,包括两个球拍的运行受同一个按键控制,如果把它们的控制分离,那么 一颗小球的畅想 就能成为一个双人游戏,玩家可以选择进行单人游戏或者双人对战;球的速度、球拍的长度不能随着游戏的进度发生变化,在今后的版本中可以考虑添加等级机制,随着分数的增加,等级也增加,从而改变球的速度和球拍的长度;游戏中没有随机事件:例如通过小球来吃其他具有特殊功能的东西等;游戏数据无法保存,无法加载历史游戏记录;游戏没有开始界面。以上都是当前版本中的不足之处,因此需要在后续版本中不断的完善。