北京工业大学 c语言毕业课程设计 报告.docx
《北京工业大学 c语言毕业课程设计 报告.docx》由会员分享,可在线阅读,更多相关《北京工业大学 c语言毕业课程设计 报告.docx(42页珍藏版)》请在冰豆网上搜索。
北京工业大学c语言毕业课程设计报告
(此文档为word格式,下载后您可任意编辑修改!
)
扫雷
学号_____110703xx___
姓名_____xxx______
指导教师______xx______
2011年12月
目录
1需求分析3
1.1功能与数据要求3
1.1.1游戏功能介绍4
1.2界面需求4
1.3开发与运行环境需求6
2概要设计7
2.1主要数据结构8
2.2程序总体结构9
2.2.1函数调用说明9
2.2.2其余子函数说明10
3详细设计11
4测试33
4.1鼠标响应测试33
4.2游戏各项数据测试34
4.3游戏时间测试34
4.4游戏界面跳转测试34
5用户手册35
6总结提高36
1需求分析
游戏名称:
挖雷游戏(MineSweeper)这是一款益智动脑游戏。
玩家只要利用鼠标点击,将随机出现在游戏区中的所有雷挖出来,即可获得游戏胜利。
1.1功能与数据要求
基本功能:
1.初始界面由控制区和游戏区两部分组成。
游戏区有一个9*9的深颜色不透明方阵,内有若干个不可见的地雷,随机分布在方格中。
随机产生雷的同时随机产生几个“秘密武器”:
防雷服或探测仪,如果挖到一个防雷服,挖雷员增加一条命;如果挖到探测仪,使用探测仪探测时,点击方格,可显示本方格以及周围八个方格里是否有雷。
使用探测仪的方法是:
用鼠标右键单击方格。
一个探测仪只能使用一次。
2程序启动后,单击“开始”按钮,则从键盘输入用户名,然后游戏开始。
3用鼠标选中任一方格,如果不是地雷,方格颜色变为浅色;如果是“秘密武器”,方格变为浅色同时工具可以使用,并在游戏信息区显示“秘密武器”的标志(例如:
红色的圆圈表示防雷服,等等)及个数;如果是地雷则爆炸,减少一条命(也即减少一个防雷服),所有命消耗完毕则游戏结束。
4每个挖雷员初始分数为0。
每标记一个非雷方格得一分。
在控制区显示当前挖雷员的当前得分。
5游戏设置时间设置,或称生命值。
时间用完则游戏结束。
6游戏可有以下结束方式:
成功结束:
当前所有非雷区都被标出,程序自动把有雷的方格标为红色,游戏结束,并显示当前玩家分数。
失败结束:
情况1:
当时间全部用完,而界面仍有非雷方格未标出,则游戏结束。
情况2:
遇到雷爆炸并已经用完所有防雷服,则游戏结束。
情况3:
游戏过程中,按结束按钮,强行终止。
7设置游戏的排行榜,显示玩家排名。
拓展功能:
1增加时间显示。
每一局限定在同一个预先设置的时间段内完成,动态记时并显示,当某一局到达限定时间,则游戏结束(但保留主界面)。
2探测仪功能增加为点击本格翻开周围的8个格子。
3当游戏成功结束后,可以进行下一局游戏。
4设计一种方法,可以显示非雷方格周边的地雷数。
1.1.1游戏功能介绍
(1)通过visualstudio2010进入扫雷游戏界面。
(2)进入游戏控制区域。
点击开始,输入用户名,开始计时,同时游戏开始。
(3)成功完成游戏的标志是:
在规定时间内,挖开所有的非雷方格。
三种情况视为失败:
情况1:
当时间全部用完,而界面仍有非雷方格未标出,则游戏结束。
情况2:
遇到雷爆炸并已经用完所有防雷服,则游戏结束。
情况3:
游戏过程中,按结束按钮,强行终止。
1.2界面需求
游戏欢迎界面中:
程序运行后,即出现欢迎界面,并显示作者姓名学号,采用闪动字体
的形式,使画面生动,按任意键进入游戏。
游戏初始界面:
游戏界面分为控制区,信息区,游戏区,此时可以点击开始,进入游戏。
游戏进行中:
游戏以失败结束画面:
1.3开发与运行环境需求
开发环境:
Visualstudio2010
运行环境:
Win7
2概要设计
游戏流程图:
2.1主要数据结构设计:
2.1.1二维数组
1、记录每个方格中信息的二维数组mine[9][9]
2、记录每个方格中信息作为备用的二维数组mine2[9][9]
3、记录每个方格中信息作为备用的二维数组mine3[9][9]
2.1.2全局变量
1intmine[9][9]
记录每个方格中信息的二维数组
2intmine2[9][9]
记录每个方格中信息作为备用的二维数组
3、intlife
记录该游戏进行中玩家生命值。
4、intmark
当前玩家的得分
5、time_tstart
初始时间
6、time_tnow
当前时间
7、inttime1
记录暂停时间
8、intb;
用于游戏信息区探测仪数量变化统计
9、intk;
用于游戏信息区防雷服数量变化统计
10、intn;
探测仪数量
11、intq;
用于游戏信息记录中玩家信息的记录
12、typedefstructrankinglist{
charname[100];
intscore;
}INFO;
玩家信息结构体,用于记录玩家信息。
13、INFOs[10];
定义排行榜最大信息保存数为10
2.2程序总体结构:
2.2.1函数调用说明
main()
功能:
主函数
调用:
jiemian();
()
功能:
绘制游戏界面
调用:
Life();
Mark();
welcome();
();
pause()
功能:
暂停游戏
调用:
mousemsg();
pause();
closeJM()
功能:
关闭界面
调用:
goodbye();
2.2.2其余子函数功能概要说明
Start()
功能:
接收玩家姓名
Life()
功能:
刷新游戏生命值
Mark()
功能:
刷新游戏当前得分
time()
功能:
记录游戏用时
zuojianleishutongji(inti,intj)
功能:
左键雷数统计
zuojianFLF_TCY(inti,intj)
功能:
左键点出防雷服,探测仪
gamewin()
功能:
游戏胜利结束界面
gameover()
功能:
游戏失败结束界面
minefield()
功能:
初始化方格信息
welcome();
功能:
浮现欢迎界面
goodbye();
功能:
退出游戏界面
3详细设计
3.1welcome函数功能:
产生一个欢迎界面,显示游戏名,作者。
使用户界面更加友好。
voidwelcome()
{
charbuf12[100]="设计人:
丛义昊";
输出屏幕提示
cleardevice();
setcolor(YELLOW);
setfont(90,0,"黑体");
outtextxy(160,50,"挖雷游戏");
setcolor(WHITE);
setfont(16,0,"宋体");
outtextxy(buf12);
实现闪烁的“按任意键继续”
intc=255;
while(!
kbhit())
{
setcolor(RGB(c,0,0));
outtextxy(255,400,"按任意键进入游戏");
c-=8;
if(c<0)c=255;
Sleep(20);
}
getch();
cleardevice();
}
3.2界面函数功能:
构造游戏初始界面,包括了游戏界面,字体,线,填充颜色,字符输出等各方面的设计。
voidjiemian()
{
initgraph();欢迎界面
welcome();
initgraph();初始化图形方式
inti,j;定义变量
charbuf1[100]="开始";
charbuf2[100]="暂停";
charbuf3[100]="结束";
charbuf4[100]="防雷服:
";
charbuf5[100]="探测仪:
";
setlinestyle(PS_SOLID,NULL,3);更改线的粗细为3
setfont(20,0,"黑体");字体设为黑体
cleardevice();
setfillstyle(LIGHTGRAY,SOLID_FILL);
rectangle(600);
rectangle(450);游戏控制区
rectangle(600);游戏信息区
rectangle(200);开始框
rectangle(300);暂停框
rectangle(400);结束框
outtextxy(buf1);指定位置输出字符串
outtextxy(buf2);
outtextxy(buf3);
outtextxy(buf4);
outtextxy(buf5);
Life();初始化生命显示
Mark();初始化得分显示
setfillstyle(BLUE,SOLID_FILL);
for(i=0;i<9;i++)画9x9的雷阵并涂色
for(j=0;j<9;j++){
rectangle(400+i*40,170+j*40,400+(i+1)*40,170+(j+1)*40);
floodfill(400+i*40+6,170+j*40+6,WHITE);
}
}
3.3hitKS函数功能:
控制开始键的响应,达到只有鼠标左键点击开始按钮才有反应的效果。
int0;
}
}
default:
continue;
}
}
}
3.4Start函数功能:
在hitKS函数执行后,跳出接受用户名的框,接受玩家从键盘输入的玩家名,并回显到游戏信息区。
voidStart()
{
chars1[100];定义字符串缓冲区,并接收用户输入
chars2[100];
InputBox(s1,100,"请输入玩家姓名:
");弹出接收用户名的框
sprintf(s2,"玩家名:
%s",s1);
outtextxy(s2);指定位置输出玩家名
now=time(NULL);初始化当前时间
}
3.5time函数功能:
通过和鼠标响应嵌在一个永真循环中,反复调用,达到不断刷新游戏信息区时间显示的效果。
voidtime()
{charbuf1[100];
start=time(NULL);
sprintf(buf1,"共70秒,已用时:
%d",time1+(int)difftime(start,now));
outtextxy(buf1);不断刷新当前时间
}
3.6minefield函数功能:
初始化雷阵方格信息,通过随机数种子控制产生不同的随机数,按照雷,防雷服,探测仪的顺序随即分配到81个方格中。
voidminefield()
{
inti,j,mineNUM=10,flfNUM=5,tcyNUM=5;初始化雷数,探测仪数,防雷服数
srand((int)time(0));产生随机数
do{
i=rand()%9;
j=rand()%9;随机位置产生雷
mine[i][j]=1;
mine2[i][j]=1;
mine3[i][j]=1;
mineNUM--;
}
while(mineNUM>0);
do{
i=rand()%9;随机位置产生防雷服
j=rand()%9;
if(mine[i][j]==0){
mine[i][j]=2;
mine2[i][j]=2;
mine3[i][j]=2;
flfNUM--;}
}
while(flfNUM>0);
do{
i=rand()%9;随机位置产生探测仪
j=rand()%9;
if(mine[i][j]==0){
mine[i][j]=3;
mine2[i][j]=3;
mine3[i][j]=3;
tcyNUM--;}
}
while(tcyNUM>0);
}
3.7LifeMark函数功能:
由于life,mark为全局变量,将LifeMark函数嵌套在任意一个可以影响life,mark值变化的子函数中,即可实现游戏信息区生命值,得分的实时更新。
voidLife()刷新游戏信息区的生命值显示
{
charbuf6[100];
sprintf(buf6,"生命值:
%d",life);
outtextxy(buf6);
}
voidMark()
{
charbuf8[100];
sprintf(buf8,"当前得分:
%d",mark);
outtextxy(buf8);输出当前得分
}
3.8pause函数功能:
嵌套在mousemsg函数中,通过用户点击暂停键区域,即可实现结束mousemsg函数的作用,在主函数中,由于pause函数在mousemsg之后,所以紧接着执行pause函数,最终通过再次点击暂停判断条件中的两个函数相互调用,达到可以反复暂停的效果。
if(m.x>150&&m.y>250&&m.x<300&&m.y<300){
点击暂停
time1=time1+(int)difftime(start,now);
return0;}
intpause()
{
if(life<=0||time1+(int)difftime(start,now)>=70)
{
return0;
}
if(mark>=71)
return0;
MOUSEMSGm=GetMouseMsg();
while(true)
{
if(MouseHit())
m=GetMouseMsg();
switch(m.uMsg)达到暂停游戏效果
{
caseWM_LBUTTONDOWN:
{
if(m.x>150&&m.y>250&&m.x<300&&m.y<300)
now=time(NULL);
mousemsg();函数相互调用
pause();
}
default:
continue;
}
}
}
3.9mousemsg函数功能:
此函数包含一个大的永真循环,是游戏设计的关键部分包括1.刷新时间显示2左键点击雷阵方格,开始、暂停、结束键的响应3右键点击使用探测仪翻开周围格子的响应4通过时间,得分,生命来判断游戏是否结束(成功or失败)。
intmousemsg()
{
inti,j,mineNUM=0;
MOUSEMSGm=GetMouseMsg();
charbuf7[100];
while(true)大循环
{
time();调用时间函数
if(time1+(int)difftime(start,now)>=70)
return0;时间到,游戏以失败结束
if(MouseHit())获取鼠标信息
m=GetMouseMsg();
switch(m.uMsg)
{
caseWM_LBUTTONDOWN:
{
setfillstyle(LIGHTBLUE,SOLID_FILL);
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
if(m.x>(400+i*40)&&m.x<(440+i*40)&&m.y>(170+j*40)&&m.y<(210+j*40))
{
zuojianleishutongji(i,j);调用雷数统计
if(mine[i][j]==1)
{
circle(420+i*40,190+j*40,15);
life--;踩雷生命减一
Life();刷新生命值
mine[i][j]=6;赋另值,防止重复点击
setfillstyle(BLACK,SOLID_FILL);
if(k>0)
{
bar(191+(k-1)*+(k-1)*20,475);游戏信息区防雷服减少显示一个
k--;
}
setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+i*40,176+j*40,WHITE);
if(life<=0)判断游戏失败的条件
return0;
}
zuojianFLF_TCY(i,j);调用防雷服,探测仪的显示函数
floodfill(406+i*40,176+j*40,WHITE);将格子颜色变浅
}
}
if(m.x>150&&m.y>250&&m.x<300&&m.y<300){
点击暂停
time1=time1+(int)difftime(start,now);
return0;
}
if(m.x>150&&m.y>350&&m.x<300&&m.y<400){
点击结束
life=0;
return0;
}
if(mark>=71)胜利条件之一,成功翻开所有格子
{gamewin();
return0;}
break;
}
由于四边及四角的特殊性,需要考虑到mine[i][j]中i,j的具体取值,所以需要分类讨论,鉴于有雷格子的特殊性,需要将其翻过后另赋为一个特殊值6,以便与翻过的其他格子区分开。
caseWM_RBUTTONDOWN:
{右键为探测仪功能,翻开本格周围9个格子,并显示雷数,标识雷的位置
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
if(m.x>(400+i*40)&&m.x<(440+i*40)&&m.y>(170+j*40)&&m.y<(210+j*40))
{
if(n>0)当有探测仪时,点击生效
{
if(b>0)控制游戏信息区的防雷服显示
{setfillstyle(BLACK,SOLID_FILL);
bar(190+(b-1)*+(b-1)*20,497);
b--;防雷服显示减一个
}
if(mine[i][j]==0)
{setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+i*40,176+j*40,WHITE);
mine[i][j]=5;
mark++;
}
if(mine[i][j]==2)
{
setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+i*40,176+j*40,WHITE);
setfillstyle(GREEN,SOLID_FILL);
circle(200+k*);
floodfill(201+k*WHITE);
circle(420+i*40,190+j*40,15);
floodfill(421+i*40,191+j*40,WHITE);
mine[i][j]=5;
life++;
mark++;
Life();
k++;
}
if(mine[i][j]==3)
{
setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+i*40,176+j*40,WHITE);
setfillstyle(RED,SOLID_FILL);
rectangle(191+b*+b*20,494);
floodfill(197+b*WHITE);
circle(420+i*40,190+j*40,15);
floodfill(421+i*40,191+j*40,WHITE);
mine[i][j]=5;
mark++;
b++;
n++;
}
if(mine2[i][j]==1)
{mineNUM++;
circle(420+i*40,190+j*40,15);
setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+i*40,176+j*40,WHITE);
mine[i][j]=6;
mine2[i][j]=6;
}
if(i>0)
以下为控制四边及四角的特殊情况(一次性翻开格子少于九个的特殊情况)
{
if(mine[i-1][j]==0)
{setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+(i-1)*40,176+j*40,WHITE);
mine[i-1][j]=5;
mark++;
}
if(mine[i-1][j]==2)
{
setfillstyle(LIGHTBLUE,SOLID_FILL);
floodfill(406+(i-1)*40,176+j*40,WHITE);
setfillstyle(GREEN,SOLID_FILL);
circle(200+k*);