关于扫雷游戏设计.docx
- 文档编号:6041913
- 上传时间:2023-01-03
- 格式:DOCX
- 页数:23
- 大小:150.87KB
关于扫雷游戏设计.docx
《关于扫雷游戏设计.docx》由会员分享,可在线阅读,更多相关《关于扫雷游戏设计.docx(23页珍藏版)》请在冰豆网上搜索。
关于扫雷游戏设计
关于扫雷游戏设计
扫地雷游戏设计
综述
在计算机逐步渗入社会生活各个层面的今天,计算机已经成为人们日常生活的一分,越来越多的人使用计算机办公、娱乐等等。
扫雷游戏是Windows操作系统自带的一款小游戏,在过去的几年里,Windows操作系统历经数次换代更新,变得越来越庞大、复杂,功能也越来越强大,但是这款小游戏依然保持原来的容貌,可见这款小游戏受到越来越多人的喜爱。
我利用TurboC编写了与它功能相仿的扫雷游戏,寓学于乐。
一、应用环境
1.1硬件环境
一台完整的电脑,包括键盘、鼠标,最小硬盘空间1GHz
1.1386,486,586及兼容机.640K基本内存;
2.11M以上扩充内存,10M以上的显示内存.
2.2软件环境
开发环境:
本系统的设计采用的是TC语言开发
Windows操作系统,TurboC2.0汉化版
二、程序的作用及设计目的
2.1程序功能
程序的功能是随机生成地雷数,通过鼠标操作玩游戏,不接受键盘,按任意键结束程序。
单击屏幕上的笑脸可以重新开始游戏。
所有地雷标出后胜利,当鼠标左键单击到地雷时失败。
2.2程序设计目的
1.培养综合运用所学知识独立完成课题的能力。
2.更深入地理解和掌握该课程中的有关基本概念,程序设计思想和方法。
3.提高对工作认真负责、一丝不苟,对同学团结友爱,协作攻关的基本素质。
4.培养勇于探索、严谨推理、实事求是、有错必改,用实践来检验理论,全方位考虑问题等科学技术人员应具有的素质。
5.培养从资料文献、科学实验中获得知识的能力,提高从别人经验中找到解决问题的新途径的悟性,初步培养工程意识和创新能力。
6.对掌握知识的深度、运用理论去处理问题的能力、实验能力、课程设计能力、书面及口头表达能力进行考核。
三、程序分析和设计
3.1游戏规则
设计10×10格区域,单击鼠标后,该格显示数字,则表示它周围8个空格内含有的地雷数,周围没有地雷的显示空白,则不能再单击了。
如果是地雷,则游戏结束。
如果判断是地雷,可以单击鼠标右键标出,显示红旗,要取消红旗标志则再单击鼠标右键,当所有地雷都标出,每个空格都处理过,了则胜利结束。
3.2游戏界面
游戏初始界面如图5-1所示,游戏中的界面如图5-2所示。
图5-1初始状态图5-2游戏中
3.3设计思路
扫雷程序主要用了一个10行10列的二维数组表示,数组的每一个元素是结构体类型,结构体中的num成员代表格内当前处于什么状态,值为1表示有雷,值为0表示已经变成空白格或者显示过数字,roundnum成员统计每个格子周围有多少地雷,flag变量主要是鼠标右键测试的标志,如果flag为1则表示格子显示红旗,这样鼠标左键点在这个格子中将无效。
算法的重点是一开始统计好每个格子周围有多少地雷,然后当鼠标左键点在没地雷的格子上时进行两种判断,如果格子周围没地,雷就先在原来的格子位置显示空白格,然后用递归的方法同样判断周围的8个格子;如果格子周围有地雷,就在该格子上显示具体的雷数。
在递归判断8个格子时,如果格子上有雷或者格子已经显示过雷数或者空白格,以及格子上有红旗标志的话,就不再对格子进行任何判断。
具体的函数流程如图5-3所示
1main()主函数
定义使用到的常数、全局变量、函数原型说明。
然后初始化图形系统,调用游戏控制函数,游戏只接受鼠标操,作按任意键结束游戏,关闭图形系统,程序结束。
2Control()游戏控制函数
调用函数GameBegin()显示游戏初始界面,调用GamePlay()为具体游戏操作过程,该函数返回有两种可能:
一种是正在玩中,提前结束游戏;一种是玩完,要么失败,要么胜利。
如果是前者,则重新开始游戏,如果是后者,则判断是否单击了笑脸,是则重新开始,
否则结束程序。
3GameBegin()画初始界面
这个函数完成初始界面的设计以及随机生成地雷数。
初始界面的主要工作是确定图的位置和方格显示的位置。
外边框的左上角坐标为(190,60),右下角坐标为(390,290),显示笑脸和地雷数的区域为(190,60)~(390,90),每个方格的宽度和高度均为16。
读者可以参照修改区域的大小。
4DrawSmile()画笑脸
利用画椭圆函数fillellipse()和bar()画笑脸,设置好填充模式。
5DrawEmpty()两种格子的显示
函数的参数为四个,确定格子的坐标i和j、模式和颜色。
格子有两种:
一种是可以单击的格子;一种是已经显示空白的格子,比前一种格子略小一些,通过参数模式和颜色来控制。
6DrawRedflag()显示红旗
用单击鼠标右键表示起地雷,起雷后显示一个小红旗。
7GamePlay()游戏过程
游戏过程主要是对鼠标按键的处理,具体算法如下:
1统计每个格子周围有多少地雷。
2如果没有按键盘则循环执行;
(1)如果单击了鼠标左键则判断:
如果鼠标单击了笑脸则游戏重新开始。
如果单击了方格,判断该格子里有红旗,则按键无效。
如果单击的格子没有显示过数字或空白,则判断;如果是地雷,游戏结束,显示地雷分布;如果不是地雷,则统计该格子周围(8个方向)的地雷数,如果周围地雷数为0,调用递归函数ShowWhite()处理周围格子的情况,显示周围地雷数或空白。
如果单击的格子周围地雷数不为0,则显示周围地雷数,将处理过的格子作标记。
如果所有格子处理完毕,游戏胜利,显示胜利信息。
(2)如果单击了鼠标右键,该格子没有红旗,则显示红旗。
如果有红旗,再击右键,则红旗消失。
(3)重复步骤
(2)直到按键结束程序。
8MineStatistics()统计地雷
统计每个格子周围的雷数,分别考虑格子处于四个角、四条边以及中间某个位置的情况。
周围指上、下、左、右、左上、左下、右上、右下。
注意程序中使用的是多个if语句,而没有使用或运算连接组成复合表达式,例如:
if(Mine[0][1].num==1)
nNUM++;
if(Mine[1][0].num==1)
nNUM++;
没有写成if(Mine[0][1].num==1||Mine[1][0].num==1)是考虑到C语言的逻辑表达式的短路问题,逻辑或只要前面的表达式为真,后面就不必判断了,这样可能造成少计地雷数。
9ShowWhite()显示无雷区的空白格
当单击了某个格子,该格子周围地雷数为0时,应该继续判断它周围8个方向的格子的周围地雷数是否为0,将这些格子都用空白显示。
所以这也是一个递归问题,将其构造为递归函数。
一个递归函数有两个要素,一个是入口参数,且是降规模的,另一个为出口参数。
本函数的入口参数为格子的坐标,表示处理哪个格子,出口参数是该格子有红旗或
者已经显示过数字或空白格子。
具体算法如下:
(1)如果当前格子有红旗或者已经显示过数字或空白格子,则返回。
(2)空白格子数减1(统计处理过多少格子)。
(3)如果周围的地雷数为0,且它不是地雷,则将它显示为空白,同时将它的状态值num置0,表示处理过;如果周围的地雷数不为0,显示周围地雷数,同时将它的状态值num置0,表示处理过(即显示过数字),返回。
(4)8个方向递归调用函数显示所有的空白格子。
10GameOver()游戏失败
如果单击了地雷,则地雷爆炸,游戏结束,显示所有的地雷,两重循环判断每个格子的状态,如果状态值为1,则为地雷,设置红色背景,实体填充模式,画圆表示地雷。
11GameWin()输出最后的胜利者结果
如果所有格子都处理过了,就表示胜利,输出youwin信息。
12鼠标处理函数
在Windows应用程序中,人们越来越离不开的输入设备是鼠标,用户拿着鼠标指指点点就完成了几乎全部的工作,利用VisualBasic、VisualC等开发工具开发Windows应用程序,系统提供了鼠标支持功能,无须程序员在这方面下功夫。
然而在DOS环境下,用户要使用鼠标必须自己加载鼠标驱动程序。
在Windows操作系统下,系统自动加载了鼠标驱动程序,但并不意味着在任何程序下都可以使用,用TurboC开发的应用程序要支持鼠标操作,则必须进行鼠标设备驱动程序的访问。
鼠标设备驱动程序的访问通过使用中断0x33访问。
本程序中所用中断0x33的功能与
参数如表5-1所示。
说明该游戏程序在WindowsXP下不支持鼠标。
四、程序测试及分析
4.1程序调试是指对程序的查错和排错。
为了便于查错、阅读,在设计该程序的过程中我们采用了结构化程序方法编辑,添加了尽可能多的注释,这就为接下来的调试过程带来了很多方便。
4.2经过仔细检查之后进行上机调试。
进行编译,如果在编译和连接过程中发现错误,屏幕上显示了出错信息,根据提示找到出错的位置,加以改正,再进行编译……如此反复,直到顺利通过编译和连接为止。
游戏开始图
游戏中
4.3在本次实习过程中碰到的编译、连接的错误主要有:
缺少变量定义,定义位置不正确、语法错误、注释的位置等。
4.4错误解决方法。
(1)缺少变量定义,定义位置不正确;
由于该程序相对来讲稍有些长,前后有些变量不容易联系起来,但是在错误信息的提示下一般还是很容易找到。
不过需要注意的是在定义的时候有些函数使用同样的变量名而表示不同的作用,因而使用要很小心,定义及定义的位置要特别留意。
为减少这样的错误我后来还是用不同的变量名来表示,结果引起的那些错误解决了。
例如:
未定义voidClose(void);/*图形关闭*/,所以输出voidClose(void);中就有错误,因为缺少定义。
(2)语法错误;
大多的语法错误在通过书本参考下能够修改。
主要是平时缺乏锻炼、不太注意而产生的。
如没有注意具体数据使用是有一定的范围限定;过分重视分号的重要性而在for、if、while语句中画蛇添足加分号;在使用文件的时候忘记将文件先打开,对打开的方式
(3)注释的位置;
程序设计中在注释的时候不能同我们平常写字一样随心所欲,我们应该注意注释的格式。
注释中不能含有c语言可执行的语句!
五、心得体会
课程设计是本科学习阶段一次非常难得的理论与实际相结合的机会,通过这次比较完整的一个程序的设计,我摆脱了单纯的理论知识学习状态,和实际设计的结合锻炼了我的综合运用所学的基础知识,解决实际问题的能力,同时也提高我查阅文献资料、对程序整体的把握等其他能力水平,而且通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,经验得到了丰富。
这是我们都希望看到的也正是我们进行课程设计的目的所在。
虽然设计内容繁多,过程繁琐但我的收获却更加丰富。
各种组件的运用,各种算法的应用,各种控件的利用我都是随着设计的不断深入而不断熟悉并逐步掌握的。
和老师以及同学的沟通交流更使我对程序整体的规划与设计有了新的认识也对自己提出了新的要求。
提高是有限的但提高也是全面的,正是这一次设计让我积累了许多实际经验,也必然会让我在未来的工作学习中表现出更高的应变能力和理解力。
顺利如期的完成本次课程设计给了我很大的信心,但是也让多不足的地方,学习其实就是一个不断完善的过程,正视自己的不足之处,在以后的工作和学习中不断的弥补这些不足之处,在以后的生活中也要保持同样的态度,不断的完善自己。
六、总结
6.1知识点
1数组的应用。
2全局变量的应用。
3按键的处理。
4递归函数。
5鼠标应用。
6.2功能扩充、
修改程序,设初级、中级、高级三个等级,初级地雷数较少,在15个以内,中级在
15到30个,高级则扩大棋盘为20×20,地雷数为30个以上。
七、参考文献
7.1郭翠英主编的《C语言课程设计实例精编》;
7.2张芳妮吕波译《C语言编程常见问题解答》;
7.3谭浩强《C程序设计题解与上机指导(第二版)》。
7.4伍俊良.VB课程设计与系统开发案例[M].北京:
清华大学出版社,2002。
附:
源程序
#include
#include
#include
#defineLEFTPRESS0xff01
#defineLEFTCLICK0xff10
#defineLEFTDRAG0xff19
#defineMOUSEMOVE0xff08
struct
{
intnum;/*格子当前处于什么状态1有雷0已经显示过数字或者空白格子*/
introundnum;/*统计格子周围有多少雷*/intflag;/*右键按下显示红旗的标志0没有红旗标志1有红旗标志*/
}Mine[10][10];
intgameAGAIN=0;/*是否重来的变量*/
intgamePLAY=0;/*是否是第一次玩游戏的标志*/
intmineNUM;/*统计处理过的格子数*/
charrandmineNUM[3];/*显示数字的字符串*/
intKeystate;
intMouseExist;
intMouseButton;
intMouseX;
intMouseY;
voidInit(void);/*图形驱动*/
voidMouseOn(void);/*鼠标光标显示*/
voidMouseOff(void);/*鼠标光标隐藏*/
voidMouseSetXY(int,int);/*设置当前位置*/
intLeftPress(void);/*左键按下*/
intRightPress(void);/*鼠标右键按下*/
voidMouseGetXY(void);/*得到当前位置*/
voidControl(void);/*游戏开始重新关闭*/
voidGameBegain(void);/*游戏开始画面*/
voidDrawSmile(void);/*画笑脸*/
voidDrawRedflag(int,int);/*显示红旗*/
voidDrawEmpty(int,int,int,int);/*两种空格子的显示*/
voidGameOver(void);/*游戏结束*/
voidGameWin(void);/*显示胜利*/
intMineStatistics(int,int);/*统计每个格子周围的雷数*/
intShowWhite(int,int);/*显示无雷区的空白部分*/
voidGamePlay(void);/*游戏过程*/
voidClose(void);/*图形关闭*/
/*主函数*/
voidmain(void)
{
Init();
Control();
Close();
}
voidInit(void)/*图形开始*/
{
intgd=DETECT,gm;
initgraph(&gd,&gm,"c:
\\tc");
}
voidClose(void)/*图形关闭*/
{
closegraph();
}
voidMouseOn(void)/*鼠标光标显示*/{
_AX=0x01;
geninterrupt(0x33);
}
voidMouseOff(void)/*鼠标光标隐藏*/
{
_AX=0x02;
geninterrupt(0x33);
}
voidMouseSetXY(intx,inty)/*设置当前位置*/
{
_CX=x;
_DX=y;
_AX=0x04;
geninterrupt(0x33);
}
intLeftPress(void)/*鼠标左键按下*/
{
_AX=0x03;
geninterrupt(0x33);
return(_BX&1);
}
intRightPress(void)/*鼠标右键按下*/
{
_AX=0x03;
geninterrupt(0x33);
return(_BX&2);
}
voidMouseGetXY(void)/*得到当前位置*/
{
_AX=0x03;
geninterrupt(0x33);
MouseX=_CX;
MouseY=_DX;
}
/*游戏开始重新关闭*/
voidControl(void)
{
intgameFLAG=1;/*游戏失败后判断是否重新开始的标志*/
while
(1)
{
if(gameFLAG)/*游戏失败后没判断出重新开始或者退出游戏的话就继续判断*/
{
GameBegain();/*游戏初始画面*/
GamePlay();/*具体游戏*/
if(gameAGAIN==1)/*游戏中重新开始*/{
gameAGAIN=0;
continue;
}
}
MouseOn();
gameFLAG=0;
if(LeftPress())/*判断是否重新开始*/
{
MouseGetXY();
if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85)
{
gameFLAG=1;
continue;
}
}
if(kbhit())/*判断是否按键退出*/
break;
}
MouseOff();
}
/*画笑脸*/
voidDrawSmile(void)
{
setfillstyle(SOLID_FILL,YELLOW);
fillellipse(290,75,10,10);
setcolor(YELLOW);
setfillstyle(SOLID_FILL,BLACK);/*眼睛*/
fillellipse(285,75,2,2);
fillellipse(295,75,2,2);
setcolor(BLACK);/*嘴巴*/
bar(287,80,293,81);
}
/*显示红旗*/
voidDrawRedflag(inti,intj)
{
setcolor(7);
setfillstyle(SOLID_FILL,RED);
bar(198+j*20,95+i*20,198+j*20+5,95+i*20+5);
setcolor(BLACK);
line(198+j*20,95+i*20,198+j*20,95+i*20+10);
}
/*两种空格子的显示*/
voidDrawEmpty(inti,intj,intmode,intcolor)
{
setcolor(color);setfillstyle(SOLID_FILL,color);
if(mode==0)/*没有单击过的大格子*/
bar(200+j*20-8,100+i*20-8,200+j*20+8,100+i*20+8);
else
if(mode==1)/*单击过后显示空白的小格子*/
bar(200+j*20-7,100+i*20-7,200+j*20+7,100+i*20+7);
}
/*游戏开始画面*/
voidGameBegain(void)
{
inti,j;
cleardevice();
if(gamePLAY!
=1)
{
MouseSetXY(290,70);/*鼠标一开始的位置并作为它的初始坐标*/
MouseX=290;
MouseY=70;
}
gamePLAY=1;/*下次按重新开始的话鼠标不重新初始化*/
mineNUM=0;
setfillstyle(SOLID_FILL,7);
bar(190,60,390,290);
for(i=0;i<10;i++)/*画格子*/
for(j=0;j<10;j++)
DrawEmpty(i,j,0,8);
setcolor(7);
DrawSmile();/*画脸*/
randomize();
for(i=0;i<10;i++)/*100个格子随机赋值有没有地雷*/
for(j=0;j<10;j++)
{
Mine[i][j].num=random(8);/*如果随机数的结果是1表示这个格子有地雷*/
if(Mine[i][j].num==1)
mineNUM++;/*现有雷数加1*/
else
Mine[i][j].num=2;
Mine[i][j].flag=0;/*表示没红旗标志*/
}
sprintf(randmineNUM,"%d",mineNUM);/*显示这次总共有多少雷数*/
setcolor
(1);
settextstyle(0,0,2);
outtextxy(210,70,randmineNUM);
mineNUM=100-mineNUM;/*变量取空白格数量*/
MouseOn();
}
/*游戏结束画面*/voidGameOver(void)
{
inti,j;
setcolor(0);
for(i=0;i<10;i++)
for(j=0;j<10;j++)
if(Mine[i][j].num==1)/*显示所有的地雷*/
{
DrawEmpty(i,j,0,RED);
setfillstyle(SOLID_FILL,BLACK);
fillellipse(200+j*20,100+i*20,7,7);
}
}
voidGameWin(void)/*显示胜利*/
{
setcolor(11);
settextstyle(0,0,2);
outtextxy(230,30,"YOUWIN!
");
}
/*统计每个格子周围的雷数*/
intMineStatistics(inti,intj)
{
intnNUM=0;
if(i==0&&j==0)/*左上角格子的统计*/
{
if(Mine[0][1].num==1)
nNUM++;
if(Mine[1][0].num==1)
nNUM++;
if(Mine[1][1].num==1)
nNUM++;
}
elseif(i==0&&j==9)/*右上角格子的统计*/
{
if(Mine[0][8].num==1)
nNUM++;
if(Mine[1][9].num==1)
nNUM++;
if(Mine[1][8].num==1)
nNUM++;
}
elseif(i==9&&j==0)/*左下角格子的统计*/
{
if(Mine[8][0].num==1)
nNUM++;
if(Mine[9][1].num==1)nNUM++;
if(Mine[8][1].num==1)
nNUM++;
}
elseif(i==9&&j==9)/*右下角格子的统计*/
{
if(Mine[9][8].num==1)
nNUM++;
if(Mine[8][9].num==1)
nNUM++;
if(Mine[8][8].num==1)
nNUM++;
}
elseif(j==0)/*左边第一列格子的统计*/
{
if(Mine[i][j+1].num==1)
nNUM++;
if(Mine[i+1][j].num==1)
nNUM++;
if(Mine[i-1][j].num==1)
nNUM++;
if(Mine[i-1][j+1].num==1)
nNUM++;
if(Mine[i+1][j+1].num==1)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 关于 扫雷 游戏 设计