您的位置:首页 > 编程语言 > Java开发

基于java的挖地雷游戏

2015-08-18 12:53 549 查看
项目简介:

模拟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都安置完以后。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: