基于java的挖地雷游戏

项目简介:

         模拟windows系统中的挖地雷游戏,采用Java开发类似的游戏。

 

游戏包含的行为:

1.      基本的游戏功能1(优先级高):

通过鼠标点击按钮,完成图片的显示:

Case1: 如果是空白,则显示空白以及与之相连的空白;

Case2: 如果是数字,则只显示数字本身;

Case3: 如果是地雷,游戏结束;

 

2.      时钟功能(优先级低):

时钟记录,在游戏过程中显示玩家到目前为止所花费的时间;

 

3.      关卡功能(优先级低):

玩家可以在容易,中,难三个等级中选择游戏的难度;

 

根据游戏行为的简单设计:

1.      参考拼图游戏,鼠标点击完成翻图,只是对于button的一个setIcon的动作;

 

2.      针对地雷阵列,为描述其中每一个的状态,需要建立一对应的二维数组,二维数组中地数字表示该位置的状态:

-1:表示本格为地雷;

0:表示本格空白;

1-8:表示本格周围有多少个地雷;

 

         说明:那么游戏的关卡难度,就是地雷阵列的大小以及地雷的多少,不同的难度只要在创建地雷二维数据时,对地雷阵列大小和地雷多少进行制定即可。

 

         创建2维数组时的顺序:

         在二维数组中首先随机地确立需要数量的地雷的位置;后续地可以简单的有两种方案,

         方案1:以地雷的位置为核心,先设定地雷周围的方格的状态,再对剩下的方格进行设定;

         每个地雷周边最多8个空格;只要将这8个处理完即可。

         那么对于每个空格而言,其对应的处理过程:

         aroundCount(int x, inty){

                   int count =0;

         if(valid(x,y)){

                            for(int i=0; i<7; i++)

                          {

                                               If(valid(x+node[i].x,y+node[i].y){

                                                        Count++;

                                               }

                          }

                            }

         }

 

                   VoidmineAround(int x, int y)

                   {

                                     for(inti=0; i<7; i++)

                                     {

                                               Inttempx = x+node[i].x;

                                               Inttempy = y+node[i].y;

                                               If(valid(tempx,tempy){

                                                        Touch(x, y,count);

                                               }

                                     }

                   }

 

         方案2:按照自上而下,自左而右的顺序,依次扫描二维数组中的每个除地雷外的格子,并且完成数值的设定;

 

         方案2的逻辑更加简单,只要数数当前方格的周围有多个个地雷即可。而方案1要先找到当前某地雷周围的方格,然后再根据方格周围有多少个地雷来设定值;但从数据的处理量而言,方案1面对的数据量更小点,所以我们还是从效率出发,选择方案1。

         扫描法中的一个重点在于:要找到当前方格的所有邻居;边界点的存在增加找邻居的困难。

 

3.       鼠标的点击动作:

每个鼠标监听类在创建时,会制定其对应的x值和y值,此点击时,可以获得本按钮的x值和y值;从而获得二维数组中对应的值,根据对应的值进行操作:

 

3.1  该值是数字1-8:直接显示;

3.2  该值是-1:游戏失败;

3.3  该值是0:显示自身的同时,找到其周围的邻居中值为0的按钮,进行显示;

 

此处使用的基本知识为遍历:

walkThrough();

此处可以采用深度优先的方式找到所有相连的值为0或数字的方格:

walkthrough(intx, int y){

         if(value(x,y)!=0)

                   return;

 

         if( isValid(x,y) && notTouched(x,y)){

                  

touch(x,y);

if(value(x,y)==0{ //为零的情况下,向8个方向扩展;

                   walkthrough(x-1, y-1); //往其他的8个方向探索;

                   walkthrough(x, y-1);

                   …

                   Walkthrough(x+1, y+1);

         }

         }

}

 

4.      判断游戏的结束:

失败的情况1:只要点击到地雷,游戏即结束;

成功的情况2:每完成一次点击后,判断当前剩下的未被touch的空格数;如果未被touch的空格数刚好等同于地雷的个数,那就说明游戏成功结束;


挖地雷游戏的实现

首先,回顾下主要的设计:

 

根据设计中的情况:

 

单元格设计:

         单元格对象box.java,比如当前单元格的x,y,以及是否被touch(即点击过)?是否设置过值?

 

方格阵列设计:

单元格组成的阵列也包含特定的属性:

1.      横向的x值和纵向的y值大小,即阵列范围;

2.      包含的地雷的个数;

3.      剩余的未被touch的方格数;

4.      阵列所对应的方格二维数组;

 

实现1:

         将单元方格作为一基本的类,box.java;包含方格的坐标已经对应的状态;并且存储对应的值;

 

实现2:

         将所有的单元方格组成的二维结构作为一基本的类,block.java;

         提供touch(x,y)方法;

         提供walkThrough方法;

         提供valid方法;

 

实现3:

         鼠标的响应类:其中主要的行为是根据点击的行为,按三种方式进行处理;

         根据点击鼠标的x和y值,获得对应方格阵列中的目标方格,在根据目标方格的值状态:

1.  如果-1:游戏结束;

2.  如果1-8:显示当前的方块;

3.  如果0:不仅显示当前的方块,还使用深度优先的策略,遍历附近其他的按钮;

如果上述三者的行为由box统一提供的话,那对于0的情况,就意味着box又要反过来依赖block;不喜欢这种相互依赖的设计;

 

如此的话,采用block类的层面来直接提供上述三种行为的支持。

 

实现4:

         界面类,gameView.java,其中包含对各个类的初始化;

         对按键的初始化;

         对block的初始化等;


扫雷游戏实操过程中

问题与解决

问题1:按钮监听类中遇到的问题,

 

public class MyButton{

         publicvoid actionPerformed(ActionEvent e){

                   boxclickedBox = blk.getBox(x, y);

                  

         if(!clickedBox.isTouched()){

                   inttempValue = clickedBox.getValue();

 

                   if(tempValue== MyConstant.MINE){

                            System.out.println("Youtouch mine, game over");

                            System.exit(0);

                   }elseif(tempValue == MyConstant.BLANK){

                            blk.walkThrough(x,y);

                   }elseif(tempValue >=1 && tempValue <=8){

                            …

                   }else{

                   }

         }

}

 

上述是对按键处理:

获得被按键的value后,然后根据value的值来进行相应的动作;

        如果踩到地雷,那相应的处理很简单;

        如果踩到数字,那也好办;

 

关键的是踩到空白该如何处理?根据我们的设计,相应的采取遍历的方式;但是除了遍历的对象外,还要考虑对按钮进行设置,对应的box设置touched;感觉此处的几个对象纠缠在一起,耦合严重。

简单想到的方式:

对box的设置touched在blk的walkThrough中完成;而对按钮的设置,则在walkThrough返回结果后完成。

如上图,观察下windows下的扫雷游戏,点击到空格后,整个图会扩散直到边界和数字;所以可认为点击到数字是点击到空白的特殊情况。

 

walkThrough的返回值可采取容器类的方式来实现。

创建用于值传递的类point.java:

public class point{

                   public point(int x, int y){

                            This.x = x; this.y =y;

                   }

                  publicint getX(){return x;}

                   public int getY(){return y;}

}

但是,此处的walkThrough属于递归调用,所以其本身不适合返回值;所以在block类中,我们再创建一用于值传递的对象validpoint;

 

问题2 GameView的显示问题:

GameView.java中的代码:

public GameView(int x, int y,int nummine){

           this.x = x;

           this.y = y;

           this.nummine =nummine;

          

           this.setTitle("扫雷v0.1");

           System.out.println("x*MyConstant.btnWidth="+x*MyConstant.btnWidth+""+"y*MyConstant.btnHeight="+y*MyConstant.btnHeight);

           this.setSize(500,500);

          

           this.setLayout(newGridLayout(10, 10));

           this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);             

           addButton();

}

public void addButton(){

           blk = new Block(x,y, nummine);

           jbtn = newJButton[x][y];

          

           for(int i=0; i<x;i++)

                    for(intj=0; j<y; j++)

                    {

                             jbtn[i][j]= new JButton();

                             jbtn[i][j].setBounds(x*MyConstant.btnWidth,y*MyConstant.btnHeight,MyConstant.btnWidth, MyConstant.btnHeight);

                             jbtn[i][j].addActionListener(newMyButton(x,y,blk,jbtn));

                             this.add(jbtn[i][j]);

                    }

         }

如上的代码在运行中出现问题:预想的10*10的图片并不会马上出现,

之所以出现这种问题:

因为JFrame容器过早显示,会导致后面的控件没有准备好就显示出来,所以需要把JFrame的显示放在最后。

对应的解决方案:让JFrame的显示放到最后,即setVisible(true)这条语句放到button都安置完以后。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值