扫雷游戏的设计与开发目录1流程规划2画面规划3鼠标使用4地雷及雷区表面探测情况5除去未靠近地雷的方块6游戏的调试7参考文献1.流程规划流程规划大致上可以分为三个部分,分别为:画面初始、游戏者按下第一个方块和为非地雷方块时展开。
流程规划如图1所示:图1整体流程规划图2.画面规划画面规划如图2所示:①④②③⑤⑥⑦⑧⑨图2说明如下:①:游戏窗口(Form)。
为了避免因改变窗口大小而造成画面呈现不美观,在这里将BorderStyle属性设定为3(双线固定对话框),即无法以窗口边缘进行窗口大小调整。
②:地雷数显示区(PictureBox)。
③:游戏状态(Image)。
④:游戏时间显示区(PictureBox)。
⑤:计数及状态区(PictureBox)。
⑥:地图区图样(Image)。
⑦:地雷区(PictureBox)。
⑧:存储图片的组件,包括游戏状态图片、地雷区图片、地雷数及秒数数字图片(Imagelist)。
⑨:秒数控制(Timer)。
游戏的详细设计3.游戏初始化当玩家开始游戏时,游戏画面如图3所示:计数及状态区地雷区图3游戏初始画面我们可以清楚的看到,游戏界面主要分为两个主要部分:1.计数及状态区;.地雷区。
首先我利用PictureBox组件,PictureBox为容器类型的组件,因此可以加入其他组件在其内。
在游戏中我利用了PictureBox组件的两个特性,分别为容器特性及立体框线,具体如下:(1)容器特性:只要容器本身显示的行为改变,在容器内的组件也会跟着改变。
当游戏初始时,地雷区的显示组件会循环执行,逐一布置在画面上,但由于执行循环时多个Image组件要显示图形,造成分时系统执行频率显示上会出现不流畅的情形,若在循环执行前,先将容器本身的Visable属性设为False,在循环执行完成后再将Visable属性设为Ture,则显示就会变得流畅许多。
(2)立体框线:通过组件本身立体框线的属性设定,可以为游戏画面的显示上营造出层次感。
然后再利用ImageList组件来存储游戏中将要使用的图片,我们可以将组件布置于窗体后编辑组件属性,如图4所示:图4通过InsertPicture和RemovePicture按钮即可编辑组件所存放的图片。
利用ImageList集合对象的Picture方法,即可将ImageList组件内的图片指定给图形显示组件,语法如下:Set图形组件. Picture=ImageList. ImageList(图片索引). Picture因为一个ImageList组件内必须存储大小相同的图片,所以在游戏中显示的图片共分为三个部分:1.数字计数图形;2.游戏状态图形;3.地雷区表示图形。
所以我们使用了三个ImageList组件来存储不同大小的图片。
接着便是对地雷区的初始化,这里我们利用Load及UnLoad指令,动态新增及删除组件。
在游戏的地雷区,我们依照游戏者自定义的地图类型,来布置未探测地雷方块。
假如设定的地图大小为20×30时,我们可以通过双循环For…Next及Load指令在程序执行阶段动态加载表示方块的组件,程序片段如下:‘加载表示地图资料的图片For y = 0 To 20 ‘地雷区高For x = 0 To 30 ‘地雷区宽Load 表示方块组件(index)‘设定组件位置……Next xNext y经过双循环的运算,程序就会产生20×30=600个组件,试想如果在程序设计阶段,就把600个组件布置在窗体上,那将是多么没有效率的事情,况且组件数量的多少,还要取决于游戏玩家设定的地雷区大小,所以利用Load指令对于大量加载同一组件的动作将有莫大的帮助。
加载组件后必须将组件做适当的布置,我们可以通过Image组件的Move属性,将组件布置于预定的位置,Move函数的原型如下:组件.Move X坐标,[Y坐标],[组件宽度],[组件高度](其中括号内表示可以省略)再配合双循环的变量值,可以控制组件布置于窗体的方向及方式,例如以下程序片段:For y = 0 To 20 ‘地雷区高For x = 0 To 30 ‘地雷区宽Load 表示方块组件(index)‘设定组件位置……组件(index).Move x *组件宽度,y *组件高度Next xNext y组件将呈现先由左至右,再由上至下布置。
若将内循环改为y值,同样的Move指令,组件的布置方向将由上而下再由左至右。
布置方向的不同,会关联到组件内含的索引值不同,相对在程序执行阶段存取组件时,所定义的组件索引值就必须考虑组件不止的方向,这样才不会造成组件存取的错误。
以由左至右再由上而下的布置方式为例,我们可以利用以下公式,求得组件索引值:组件索引值=(X坐标+Y坐标*数组宽度)这样,游戏界面的初始化工作就基本完成了,下面就是地雷的随机产生。
3.雷区的布置当游戏界面初始化完成后,这时在地雷区中并未产生地雷,只有当玩家在地雷区中第一次点下左键后,才会在地雷区中随机的布置当前游戏难度下应该产生的地雷总数,其主要用意在于不让玩家第一次就踩到地雷,这样在某种程度上可以提高玩家游戏的气愤。
具体实现如下所示:'判断地雷区是否处于可动作状态If isDie = False And isFinal = False Thenxxx = index Mod MAP_X '标示动作图片的坐标yyy = index \ MAP_X'判断为左键且该方块为未探测状态If Button = 1 And mapFaceArr(xxx, yyy) = 1 Then'判断游戏是否等待启动If isStart = False ThencMINE_NUM = MINE_NUMisStart = TrueTimer1.Enabled = True'布置地雷Do While cMINE_NUM > 0rX = Rnd() * (MAP_X - 1)rY = Rnd() * (MAP_Y - 1)'判断数组中(rX,rY)为非地雷及'非点选的方块坐标时If mapArr(rX, rY) <> 9 And _Not (rX = xxx And rY = yyy) ThencMINE_NUM = cMINE_NUM - 1mapArr(rX, rY) = 9'地雷外围数字各加一For xx = rX - 1 To rX + 1For yy = rY - 1 To rY + 1If xx >= 0 And xx <= MAP_X And _yy >= 0 And yy <= MAP_Y ThenIf mapArr(xx, yy) <> 9 And _Not (xx = rX And yy = rY) ThenmapArr(xx, yy) = mapArr(xx, yy) + 1End IfEnd IfNext yyNext xxEnd IfLoopEnd If游戏中主要模块的介绍与使用3.鼠标使用在游戏过程中,我们利用鼠标所发出的信息了解游戏者的意图,进而作出相对应的动作。
在MouseDown与MouseUp事件中,可以捕捉鼠标所按下或放开的按键为何、鼠标光标在该组件上的坐标及是否同时按下辅助键等。
函数原型如下:组件名称_MouseDown(index As Integer, _Button As Integer, _Shift As Integer, _ x As Single, _y As Single)组件名称_MouseUp(index As Integer, _Button As Integer, _Shift As Integer, _ x As Single, _y As Single)在参数列中,Button参数值表示鼠标上的按狃数值。
其意义如下:1:左键 2:右键倘若同时按下不止一个按键时,则传回数值为按键数值相加,例如同时按下左键及右键,则Button值为1+2=3在本游戏中,我们利用右键的MouseDown事件来标示“已标示”方块,利用左键的MouseDown事件,来标示游戏者准备按下的方块,再利用左键的MouseUp 事件来确定翻开的方块。
这样的用意在于,假如游戏者发现按下的方块是错误的,此时只要不松开左键,同时按下右键,该方块就会被标示为“已标示”方块,若再松开左键,则该方块因为已成为“已标示”方块,所以就无法翻开。
在窗口的软件中,鼠标的应用是不可或缺的,但鼠标固然好用,如果程序设计不当,也可能造成使用者的不便。
通常鼠标在软件的应用上经常使用MouseUp 事件来作为确定使用者的操作意图,而只把MouseDown事件当做标示的用途(用意就如同前面所提),只是为给使用者一个反悔的机会。
游戏的操作方面主要以鼠标为主,当鼠标指针对准未翻开的方块按下左键时即表示翻开方块:If Button = 1 Then '鼠标左键If mapFaceArr(xxx, yyy) = 1 ThenCall setMineImage(index, 10)Set iState.Picture = ilSmile.ListImages(3).PictureEnd If当鼠标指针对准未翻开的方块按下右键时即表示标示或疑示地雷,反复按下右键则方块会以“未标示”→“标示”→“疑似”三者关系不断循环:If Button = 2 Then '鼠标右键If mapFaceArr(xxx, yyy) = 1 Then '未探测mapFaceArr(xxx, yyy) = 2MINE_NUM_LABEL = MINE_NUM_LABEL + 1Call setMineImage(index, 13)Call setNowMinesElseIf mapFaceArr(xxx, yyy) = 2 Then '标示mapFaceArr(xxx, yyy) = 3MINE_NUM_LABEL = MINE_NUM_LABEL - 1Call setMineImage(index, 14)Call setNowMinesElseIf mapFaceArr(xxx, yyy) = 3 Then '疑似mapFaceArr(xxx, yyy) = 1Call setMineImage(index, 9)End If4.地雷及雷区表面探测情况在游戏设计上,我利用了两个二维数组分别记录地雷的分布情况及雷区表面探测情形,如图5和图6所示:图5标示地雷分布情况图6标示地雷探测情况因为两个数组维数皆为2,所以我们通过双循环做数据的对比工作。