在之前的文章中,我对一颗小球的畅想 v1.0 版本进行了实现,详细点击这里:一颗小球的畅想 v1.0,在 v1.0 版本中,实现了弹球游戏的基本功能需求,在文章的末尾,我也留了些坑,打算有时间慢慢填,本章将继续对 v1.0 版本功能上进行增强,这个版本暂且定为 v1.1。



1、游戏运行效果图

首先上图,查看运行效果。


java 设计一个小球碰到墙反弹的游戏 java弹球游戏设计报告_Racket


程序模块划分如下

java 设计一个小球碰到墙反弹的游戏 java弹球游戏设计报告_当前版本_02

  • Constant 类:用于存放游戏中的常量数据
  • Ball 类:球类
  • GameView 类:游戏视图类
  • Racket 类:球拍类
  • Rule 类:游戏规则类
  • GameApplication 类:游戏启动类


2、历史版本

一颗小球的畅想 v1.0



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、总结

至此,我们就实现了游戏的暂停和继续,小球速度和方向随机,小球实现分数统计三个功能,但在功能上仍有许多不足之处,包括两个球拍的运行受同一个按键控制,如果把它们的控制分离,那么 一颗小球的畅想 就能成为一个双人游戏,玩家可以选择进行单人游戏或者双人对战;球的速度、球拍的长度不能随着游戏的进度发生变化,在今后的版本中可以考虑添加等级机制,随着分数的增加,等级也增加,从而改变球的速度和球拍的长度;游戏中没有随机事件:例如通过小球来吃其他具有特殊功能的东西等;游戏数据无法保存,无法加载历史游戏记录;游戏没有开始界面。以上都是当前版本中的不足之处,因此需要在后续版本中不断的完善。