翻看了下以前大学学习的一些小项目,突然发现有个项目比较有意思,觉得有必要把它分享出来。当然现在看来,里面有很多的不足之处,但因博主现在已经工作,没有时间再去优化。这个项目就是利用C#编写一个Windows系统下的扫雷小游戏。
首先讲下扫雷小游戏的玩法:
(1)扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。
(2)当点开的格子不是地雷区域的时候,该格子会显示一个数字,该数字表示的含义就是该格子周边有多少个地雷。
(3)同时点开的如果非地雷的格子,周边连贯的非地雷区域都会自动被扫描打开,直到遇到旁边有雷区的时候停止。
(4)当你判断出格子是地雷的时候,你可以使用鼠标右键将该块方格标记为雷区。当不确定的时候,你可标记个问号以待确定。
下面来说下我大学时候实现这个扫雷小游戏的思路:
(1)因为雷区是一个个格子联合组成的,那我们可以使用winform程序自带的系统按钮控件Button来实现雷区方格。
(2)代表雷区方格的Button按钮需要实现下面几个事件:鼠标左键点击扫雷事件,鼠标右键点击标记雷区事件,鼠标右键点击标记问号区域事件。
(3)为了更好的实现游戏的可玩性,增加一个自由设置地雷数量的小功能,可自行设置雷区包含的地雷数量,设置完成后,自动刷新界面,重新部署地雷。
(4)我们将雷区的方格存储在一个全局的二维数组中,Form窗体在初始化的时候,自动生成面板区域的Button按钮列表。
(5)为了实现每次玩游戏的时候,地雷分布不一致,我们在Button列表生成后。随机抽取出某些Button按钮作为地雷分布点,并记录该Button的雷区属性为含有地雷。
(6)算法中的关键:递归算法计算雷区。当点击某个方格的时候,如果该方格是雷区,则直接Game Over,如果不是的话,则我们需要一个算法去计算旁边区域的地雷数量,以及旁边区域没有地雷的区域,当没有地雷的区域连成一片的时候,我们需要使用递归算法,去查找二维数组,找到对应的连片非雷区,将之打开。
(7)如何设置方格的状态:当鼠标左键点击的方块区域非雷区的时候,我们将Button按钮的属性设置为Disabled即可呈现打开的状态。当鼠标左键打开的方格是雷区时候,此时我们可以将所有地雷区域块的Button的背景图设置为地雷图片,并播放相应的爆炸音效,弹出游戏终止界面即可。当鼠标右键标记雷区或者待确定区域的时候,只需要更改Button的背景图即可。当然上述所有点击操作,都得判断Button方格区域当前的状态值:初始化状态、已标记为待确定状态、已标记为雷区。
游戏的最终效果图如下:
我们下面来剖析下几个关键点,因为代码量比较多,我就不全部详细剖析了。
首先我们定义一个LeiButton类,这个类继承于系统控件Button,增加x,y,youlei三个字段,x表示二维数组的第一个索引,y表示二维数组的第二个索引值,youlei用于标记Button方块区域按钮的状态(0表示无雷,1表示有雷)。同时我们使用Button按钮类自带的一个Tag属性标记该方块区域是否被翻开。具体定义如下:
然后我们在窗体对象Form类中定义一些常用的变量之类,如下图,都有相应注释
下面我们来看下生成Button的二维数组,即生成雷区的Button列表。我们需要在Form中添加GroupBox组件,然后将动态生成的Button列表添加到这个groupbox组件中。生成Button的二维数组方法体如下:
生成完Button列表后,我们就开始部署地雷了,地雷随机部署到Button列表中,部署地雷的方法如下:
到了这一步,我们就应该将雷区的界面渲染出来了,这时候我们可以将上面两个方法放入窗体的Form_Load事件中即可渲染出游戏界面。如下所示
我们继续,下面写扫雷的算法,当鼠标左键点开某个方格的时候,如果该方格不是雷区,那我们需要计算该方格周边的地雷数量,计算方法如下:
下面是个递归计算的核心算法,非常关键。当我们点开的方格非雷区的时候,周边连片的非雷区的方格块会被打开。这一块的核心算法参考下列代码,row表示行,col表示列
下面我们来添加鼠标的点击事件,我这边采用的是bt_MouseUp事件来处理。点击后,我们首先判断游戏是否结束,如果没结束,则进行下列操作,获取到被点击的按钮的x,y值以及点击事件按下的键值(判断按下的是鼠标左键还是右键)。x,y值获取到了,我们就可以到Button二维数组中找到对应元素。
假如点击的是鼠标左键,则我们进行扫雷操作,具体的代码如下:
如果按下的是鼠标右键,则是标记方块是雷区或者待确定区域,具体代码如下:
最后再给出一个判断是否扫雷完毕的方法。
扫雷游戏的设计大概到此结束,中间还有很多可以优化的地方,比如将扫雷的逻辑代码抽离Form类独立出来等,这些都靠读者自行去优化了。