Java实现简易黄金矿工

项目地址

  • 点击图片跳转到项目源码地址。

游戏玩法

  • 本游戏仿制于童年经典游戏黄金矿工。
  • 主要操作有点击鼠标右键和点击鼠标左键。
  • 在游戏进行界面,点击鼠标左键可伸长钩子抓取物体,在抓取到物体后点击鼠标右键可以使用药水,药水根据抓取的物体的种类不同有两种不同的效果:如果抓取到金块,则效果为加速钩子的收回;如果抓取到的物体是石块,则效果为石块从钩子上消失(无声爆破石块。。。)
  • 游戏的积分设置:金块按照大小分为三种,积分从小到大依次为1,2, 4。每一关在规定时间内使积分达到目标积分则可通关,目前设置了8关。抓到石块没有积分。
  • 游戏难度设置:抓取到越大的金块,钩子收回的速度越慢。抓到石块时,钩子收回的速度最慢。
  • 游戏主要界面有三个:
    • 游戏开始前界面:打开游戏进入该界面,点击鼠标右键即可正式开始游戏
    • 游戏进行中界面:游戏运行界面,通过鼠标点击控制矿工抓取金块。
    • 游戏商城界面:在每一关通关后,进入商城界面,在此处可以通过点击鼠标右键用积分购买一瓶药水。每一关只能购买一瓶药水,并且药水的价格是每一关随机的,所以尽可能获得更高的分数,以便通关后有能力购买药水。

游戏实现思路

  • 总的来说,这个简易的游戏采用面向对象的思想开发,所以我们就要思考这个游戏中有一些什么对象和这些对象的属性和行为?
  • 游戏中的对象:
    • 首先我们要知道这整个游戏是运行在一个窗口中,所以要有一个窗口对象:GameWindow
    • 其次在整个游戏中首先映入眼帘的就是游戏的背景,所以有一个背景对象:Bg
    • 游戏的主要模式就是用钩子抓取物体,而钩子的实质是一条线,所有有一个线对象:Line
    • 最后就是代表金块,石块等物体的物体对象:Object
  • GameWindow对象:
    • 属性:
      • 在游戏窗口中,要包含其它所有对象,所以在GameWindow对象中要包含,Bg, Line, Object对象,其中因为一个窗口中会同时存在多个物体,所以要用一个集合来存储多个Object对象.
      • 此外,因为游戏有多种状态和界面,所以要有一个标志游戏状态的属性。
    • 行为:
      • 整个GameWindow主要实现三个功能:控制游戏窗口状态、监听鼠标动作、绘制物体和图片
  • Bg对象:
    • 属性:
      • 因为在玩家的整个游戏过程中,有很多要全程保存的信息,考虑到背景对象是一直不发生大改变的,所以将玩家游戏过程中的信息记录在这个对象中,如:游戏分数,游戏时间,药水数量,药水价格等。
    • 行为:
      • Bg对象的变化代表着游戏状态的变化,所以背景对象除了绘制背景图片和书写一些游戏信息外,还有游戏判断游戏计时是否结束,重新开始游戏这些涉及游戏状态改变的功能。
  • Line对象
    • 属性:
      • 线对象的属性主要都是描述线在游戏中的状态的,如:线的起始坐标,线的长度,线的角度等。
    • 行为:
      • 绘制不同游戏状态下的线
      • 检测线与物体的接触状态来控制游戏状态切换
  • Object对象
    • 属性:
      • 主要是标识物体性质的属性,如:物体的长宽,质量属性(用于计算线的拉取速度),积分价值,类型标识(金块还是石块),状态标识(是否被抓取),物体图片等。
    • 行为:
      • 物体并没有特殊的行为
    • 继承关系:因为游戏中有两种不同的物体(金块、石块),所以二者分别继承自Object对象,并有自己的一些独特属性
      • Gold对象:金块对象,通过内部类实现三种不同的金块
      • Rock对象:石块对象。

一些技术点

  • 游戏界面的绘制通过Java提供的AWT(Abstract Window Toolkit)工具包和AWT的升级版Swing用户界面库来实现。
  • Java Swing绘图时的坐标和平常意义的不太一样:在图形坐标系中,其原点位于构件的左上角,坐标轴沿向下和右的方向增长,小圈代表坐标,正方形代表像素,坐标位于像素之间。

双缓存解决图像闪动问题

  • 问题出现的原因:因为整个窗口中有多个图像,它们是依次调用paint方法一个一个地画上去的,不同图像绘画的时间间隔就导致了闪动问题。
  • 解决问题的思路:用一个新的画布,先将所有的图像都绘制到这个画布上,然后再将这个画布整体绘制到窗口中去,这样就不会有不同图像绘制的间隔时间,从而解决闪动问题。
  • 代码分析

//定义画布,用于实现双缓存
Image offScreenImage;

/**
 * 传入画笔,绘制图片
 */
public void paint(Graphics g) {
    //初始化实现双缓存的画布,和窗口大小相同
    offScreenImage = this.createImage(768, 1000);

    //创建属于画布的画笔,调用这个画笔就是向这个画布上绘制
    Graphics gImage = offScreenImage.getGraphics();

    //将各种图案绘制到画布中,先画物体再画线使抓取时线在物体上面
    bg.paintSelf(gImage);

    //仅在游戏状态才绘制物体和钩子
    if(state == 1) {
        //遍历金块集合,将每个金块绘制出来
        for(Object obj : objs) {
            obj.paintSelf(gImage);
        }
        line.paintSelf(gImage);
    }

    //将画布绘制到窗口中,使用传入的画笔
    g.drawImage(offScreenImage, 0, 0, null);

}

总结

  • 虽然是一个非常简单的游戏,但是这之中面向对象开发思想得到了淋漓尽致地体现。此外,今后对这种游戏的开发思路也有了一个大致地了解,以后玩游戏的时候看着游戏种种设计,也有了一个思考其实现方法的方向。