c++贪吃蛇课程设.docx
《c++贪吃蛇课程设.docx》由会员分享,可在线阅读,更多相关《c++贪吃蛇课程设.docx(32页珍藏版)》请在冰豆网上搜索。
c++贪吃蛇课程设
《面向对象程序设计》
课程设计
设计名称贪吃蛇
姓名王刚
指导教师张静
班级信息管理与信息系统班
2016年6月9日
目录
第一章应用程序的介绍-1-
1.1选题背景-1-
1.2关于编译软件-1-
1.3关于兼容性-1-
第二章概要设计-2-
2.1程序结构-2-
2.2程序流程-3-
第三章游戏实现-4-
3.1游戏界面控制-4-
3.2初始化食物-4-
3.3游戏控制-4-
3.4游戏设置-5-
第四章结果与讨论-6-
4.1程序运行-6-
4.2错误调试与分析-6-
致谢-6-
附录-7-
第一章应用程序的介绍
1.1.选题背景
贪吃蛇是家喻户晓的益智类小游戏,选择这个题目一是为了将自己的所学知识加以运用,二是一直以来贪吃蛇这个游戏就深深地吸引着我,它的制作方法对于以前的我而言都是很神秘的。
我希望通过自己的所学知识把它剖析开来,真真正正的了解它的本质和精髓。
虽然我的编程能力不是很强,但是我有信心,在这次学习中我将从实践和实际的项目中提高自己的编程能力。
因此我选定了这个题目。
1.2关于编译软件
本程序采用MicrosoftVisualC++6.0的中文版本进行编译。
VisualC++6.0是Microsoft公司推出的基于Windows操作系统的可视化C++编程工具,尽管Microsoft公司推出了.NET平台的集成开发环境,但由于其良好的界面和可操作性,加上支持标准C/C++规范,但仍有相当多的编程人员使用VisualC++6.0进行应用系统的开发。
1.3关于兼容性
本程序经过调试,可以在XP系统下编译运行,也可以在VisualC++6.0下运行,界面稍有不同,但不影响运行结果。
第2章概要设计
2.1程序结构
根据分析,贪吃蛇这个程序一共要实现如下几个功能,包括游戏方面开始游戏、暂停游戏以及停止游戏,音乐音效的添加与控制,游戏帮助提示与英雄榜的显示等等。
具体的程序结构如下面的图1-1所示。
图2-1贪吃蛇结构图
2.2程序流程
根据分析后的贪吃蛇结构设计出相应的贪吃蛇流程。
贪吃蛇的内容主要包括:
游戏开始,随机出现食物;按下ToolBar中的暂停按钮或Space键可以实现暂停功能;按下帮助键或ToolBar中的“?
”键可获得游戏帮助说明;可播放背景音乐和音效并可通过菜单以及ToolBar控制其播放或停止等等。
图2-2贪吃蛇流程图
第三章游戏实现
3.1游戏界面控制
贪吃蛇游戏的游戏界面包括背景图片、蛇身体的绘制、蛇移动范围的绘制等等。
其中贪吃蛇的身体用什么方法绘制,才可以使得其在游戏过程中可以实现“吃”的功能是很重要的。
因此在游戏界面的初始绘制时就必须考虑到游戏时可能遇到的问题。
本程序采用点数组CArraym_ysBody来存储贪吃蛇,点数组的功能很强大,可以添加点,同时可以获得蛇的长度,对于而后进行游戏中控制蛇的颜色以及音效的播放等都有很大的帮助。
3.2初始化食物
确定用点数组存储贪吃蛇以后,贪吃蛇的食物如何达到随机出现,并且能够按照网格式与蛇头无偏差相接就是一个亟待解决的问题。
随机出现应采用rand()函数来实现,而食物与蛇头无偏差相接则利用坐标来解决。
设置两个整型变量m_ysX,m_ysY作为食物出现的点的坐标,令m_ysX=rand()%30,,m_ysY=rand()%40即可。
使随机出现的点能够整除最小网格,也就是使食物与蛇头无偏差相接。
再由食物坐标(m_ysX,m_ysY)与蛇头坐标是否相同判断蛇是否“吃”到了食物,设置判断标签ysTag,如果吃到了,ysTag为1,则再出现下一个食物,反之,如果没吃到,则不出现食物直到标签为1为止。
最后,再将(m_ysX,m_ysY)赋给m_ysFood作为食物坐标,以便在其他函数中调用。
3.3游戏控制
开始游戏后的重点是如何用键盘来控制蛇的移动并传递到OnTimer(UINTnIDEvent)函数中去以及判断蛇是否死亡。
首先说明键盘与蛇的响应,设置一个方向控制变量m_ysDirect,再添加OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)函数来实现键盘消息的传递,按下不同的键盘按键,m_ysDirect会相应的改变,再利用switch语句在OnTimer(UINTnIDEvent)函数中对坐标进行相应改变即可。
其次来解释一下如何判断蛇的死亡,由于蛇的身体是由点坐标数组构成的,因此判断蛇是否死亡其本质就是判断蛇头的坐标是否与游戏边框相同或者蛇头坐标是否与蛇自己的身体相同。
该过程也在OnTimer(UINTnIDEvent)函数中写入即可,设置一个判断死亡变量ysTag1,当按下向下键时,蛇纵坐标不断自加,
如果ysTag1为1,则说明蛇已经死亡,应当弹出对话框提示死亡,输出得分(如图3-4),同时还可以根据玩家的得分数相应的改变对话框中的话语(XP系统下)。
我们看到蛇身体的颜色发生了变化,不再是初始状态的绿色,而是变为了蓝色,这是在OnDraw(CDC*pDC)函数中设置的,设置变量获取蛇身长度,随着长度的增加,蛇的颜色发生相应改变,最终会变为表示危险的红色。
并且伴随着贪吃蛇挂掉,播放不同的音乐,如果高于70分,则放带有掌声鼓励的高分音乐的IDR_YS_HIGHSCORE,反之,则播放蛇被撞死的电子音乐IDR_YS_LOWSCORE。
播放音乐的函数用包含在头文件mmsystem.h中的PlaySound函数。
此外,游戏开始还需要计时、计分以及暂停等功能。
这些功能都比较简单,游戏时间和分数分别用两个变量m_ysTime和m_ysScore来记录,应用pDC->TextOut函数来输出即可。
至于暂停和继续的功能实现,只需要暂停和恢复计时器就可以了,实现暂停功能即KillTimer
(1)并同时令控制暂停变量为m_yspausectrl为0即可。
3.4游戏设置
这里的游戏设置主要是指游戏的等级以及音效音乐的播放控制。
关于这三个量,我们已经予以了定义,只需要在按下相应键盘或鼠标消息的时候,将变量值进行改变,再利用这些值控制相应功能的运行。
第四章结果与讨论
4.1程序运行
程序开始运行后会进入游戏界面,但是不会立即进行游戏,单击菜单的“开始”才会开始游戏。
在游戏开始前,玩家可以根据自己的喜好,通过菜单或者工具栏设置游戏等级等。
在游戏过程中,按下Space键就会暂停游戏,再按下Space键则会继续游戏。
图4-1所显示的是XP系统下菜单的样式,以及单击菜单开始。
开始游戏了,小蛇越来越长,颜色也有所不同了。
颜色的改变预示着游戏的难度加大了,并且,不同的最终得分会产生不同的死亡评语。
在前面显示了贪吃蛇死亡的样子,其中因为该局游戏得分比较低,因此得到的评语是“你才得了这么两分!
”,而如果得分较高,就会得到更好的评语,最好的评语是“牛!
”。
如果不太会玩贪吃蛇这款游戏,那么可以单击菜单“帮助—〉游戏说明”,寻求帮助。
4.2错误调试与分析
本程序由于经常调用Invalidate()函数重绘窗口,因此在游戏过程中频闪的非常严重。
查阅了很多资料,双缓冲技术可以解决这个问题,但是如果采用双缓冲技术,暂时还不能克服背景的问题,因为在双缓冲技术的应用中,背景是被强制默认为颜色,而不是图片。
我尝试改变了一下,但是没有成功,所以这个问题还没有解决。
希望老师多多给予意见。
附录
Main.
#include
#pragmahdrstop
USERES("Snake.res");
USERC("Snake_Res.rc");
USEUNIT("UnitSnake.cpp");
USEFORM("UnitTest.cpp",FormMain);
USEFORM("UnitEnterName.cpp",FormEnterName);
USEFORM("UnitAbout.cpp",FormAbout);
WINAPIWinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TFormMain),&FormMain);
Application->Run();
}
catch(Exception&exception)
{
Application->ShowException(&exception);
}
return0;
}
1.
#include
#pragmahdrstop
#include"UnitAbout.h"
#pragmapackage(smart_init)
#pragmaresource"*.dfm"
TFormAbout*FormAbout;
__fastcallTFormAbout:
:
TFormAbout(TComponent*Owner)
:
TForm(Owner)
{
LabelProg->Font->Size=12;
LabelHome->Font->Color=clBlue;
LabelHome->Font->Style=LabelHome->Font->Style<BnOKDefProc=BnOK->WindowProc;
BnOK->WindowProc=BnOkWndProc;
LabelHomeDefProc=LabelHome->WindowProc;
LabelHome->WindowProc=LabelHomeWndProc;
}
void__fastcallTFormAbout:
:
LabelHomeClick(TObject*Sender)
{
ShellExecute(Handle,"open",LabelHome->Caption.c_str(),0,"",SW_SHOWNORMAL);
}
void__fastcallTFormAbout:
:
LabelHomeWndProc(Messages:
:
TMessage&Message)
{
if(Message.Msg==CM_MOUSEENTER)
LabelHome->Font->Color=clRed;
elseif(Message.Msg==CM_MOUSELEAVE)
LabelHome->Font->Color=clBlue;
LabelHomeDefProc(Message);
}
void__fastcallTFormAbout:
:
BnOkWndProc(Messages:
:
TMessage&Message)
{
if(Message.Msg==CM_MOUSEENTER)
BnOK->Font->Color=clRed;
elseif(Message.Msg==CM_MOUSELEAVE)
BnOK->Font->Color=clWindowText;
BnOKDefProc(Message);
}
2.
#include"UnitSnake.h"
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall0[]={{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall1[]={{5,10,23,10},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall2[]={{10,5,10,16},{18,5,18,16},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall3[]={{10,5,10,16},{18,5,18,16},{5,10,23,10},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall4[]={{5,6,23,6},{5,14,23,14},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall5[]={{5,6,23,6},{5,14,23,14},{14,7,14,13},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall6[]={{10,0,10,16},{18,5,18,20},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall7[]={{0,6,23,6},{5,14,27,14},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall8[]={{6,5,6,20},{20,5,20,20},{13,0,13,16},{-1}};
TSnakeBuf:
:
TWallTSnakeBuf:
:
Wall9[]={{0,6,15,6},{21,0,21,9},{12,14,27,14},{6,12,6,20},{-1}};
TSnakeBuf:
:
TWall*TSnakeBuf:
:
Walls[]={TSnakeBuf:
:
Wall0,TSnakeBuf:
:
Wall1,TSnakeBuf:
:
Wall2,TSnakeBuf:
:
Wall3,TSnakeBuf:
:
Wall4,TSnakeBuf:
:
Wall5,TSnakeBuf:
:
Wall6,TSnakeBuf:
:
Wall7,TSnakeBuf:
:
Wall8,TSnakeBuf:
:
Wall9};
TSnakeBuf:
:
TBmpPosTSnakeBuf:
:
BmpPos[]=
{
//WallBeanSuperHeadHorzVertCrnULCrnURCrnDLCrnDRTailUTailDTailLTailRStage
{{{4,1},{4,2},{5,2},{5,1},{4,0},{5,0},{0,1},{1,1},{0,2},{1,2},{3,1},{2,2},{2,1},{3,2},{5,2}}},
{{{0,0},{1,0},{3,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{3,0}}},
};
TSnakeBuf:
:
TSnakeBuf()
{
_Snake=0;
_iBeanNo=0;
_iStageBeans=200;
_iScore=0;
_bGameOver=false;
_bEndStage=false;
memset(_Units,0,sizeof(_Units));
memset(_DispBuf,0,sizeof(_DispBuf));
}
TSnakeBuf:
:
~TSnakeBuf()
{
ClearSnake();
}
voidTSnakeBuf:
:
ClearSnake(void)
{
if(_Snake)
{
TSnakeNode*toDel;
_Snake->Prev->Next=0;
while(_Snake)
{
toDel=_Snake;
_Snake=_Snake->Next;
deletetoDel;
}
_Snake=0;
}
}
voidTSnakeBuf:
:
InitSnake(void)
{
ClearSnake();
_Snake=newTSnakeNode;
TSnakeNode*nd=newTSnakeNode;
_Snake->x=UnitX/2;
_Snake->y=UnitY-2;
_Snake->Next=nd;
_Snake->Prev=nd;
nd->x=UnitX/2;
nd->y=UnitY-1;
nd->Next=_Snake;
nd->Prev=_Snake;
}
voidTSnakeBuf:
:
StepMove(intd)
{
if((_Snake)&&(d)&&(!
_bGameOver)&&(!
_bEndStage))
{
TSnakeNodeNewPos=*_Snake;
switch(d)
{
casesdUp:
NewPos.y--;break;//up
casesdDown:
NewPos.y++;break;//down
casesdLeft:
NewPos.x--;break;//left
casesdRight:
NewPos.x++;break;//right
default:
return;//donothing
}
if((NewPos.x<0)||(NewPos.y<0)||(NewPos.x>=UnitX)||(NewPos.y>=UnitY))
{
_bGameOver=true;
return;
}
if(GetDispBuf(NewPos.x,NewPos.y)==sbnWall)
{
_bGameOver=true;
return;
}
if((GetDispBuf(NewPos.x,NewPos.y)>=sbnHead)&&(GetDispBuf(NewPos.x,NewPos.y){
_bGameOver=true;
return;
}
boolbEat=GetUnit(NewPos.x,NewPos.y)==sbnBean||GetUnit(NewPos.x,NewPos.y)==sbnStage;
SetUnit(NewPos.x,NewPos.y,sbnNone);
if(bEat)
{
TSnakeNode*NewNode=newTSnakeNode;
NewNode->x=NewPos.x;
NewNode->y=NewPos.y;
NewNode->Next=_Snake;
NewNode->Prev=_Snake->Prev;
_Snake->Prev->Next=NewNode;
_Snake->Prev=NewNode;
_Snake=NewNode;
_iScore+=ssEat;
}
else
{
_Snake=_Snake->Prev;
_Snake->x=NewPos.x;
_Snake->y=NewPos.y;
}
DrawSnake();
if(bEat)
if(!
GenBean())
{
_bEndStage=true;
_iScore+=ssStage;
}
}
}
intTSnakeBuf:
:
GetDispBuf(intx,inty)
{
if((x>=0)&&(x=0)&&(yreturn_DispBuf[y][x];
return0;
}
intTSnakeBuf:
:
GetUnit(intx,inty)
{
if((x>=0)&&(x=0)&&(yreturn_Units[y][x];
return0;
}
voidTSnakeBuf:
:
SetUnit(intx,inty,intn)
{
if((x>=0)&&(x=0)&&(y_Units[y][x]=n;
}
voidTSnakeBuf:
:
DrawSnake(void)
{
memcpy(_DispBuf,_Units,sizeof(_Units));
if(_Snake)
{
TSnakeNode*lpNode=_Snake->Next;
_DispBuf[_Snake->y][_Snake->x]=sbnHead;
while((lpNode)&&(lpNode!
=_Snake))
{
if(lpNode->Next==_Snake)
{
if(lpNode->y==lpNode->Prev->y)
_DispBuf[lpNode->y][lpNode->x]=(lpNode->xPrev->x?
sbnTailL:
sbnTailR);
else
_DispBuf[lpNode->y][lpNode->x]=(lpNode->yPrev->y?
sbnTailU:
sbnTailD);
}
elseif(lpNode->y==lpNode->Prev->y)
{
if(lpNode->y>lpNode->Next->y)
_DispBuf[lpNode->y][lpNode->x]=(lpNode->xPrev->x)?
sbnCornDL:
sbnCornDR;
elseif(lpNode->yNext->y)
_DispBuf[lpNode->y][lpNode->x]=(lpNode->xPrev->x)?
sbnCornUL:
sbnCornUR;
else
_DispBuf[lpNode->y][lpNode->x]=sbnHorz;
}
else
{
if(lpNode->xNext->x)
_DispBuf[lpNode->y][lpNode->x]=(lpNode->yPrev->y)?
sbnCornUL:
sbnCornDL;
elseif(lpNode->x>lpNode->Next->x)
_DispBuf[lpNode->y][lpNode->x]=(lpNode->yPrev->y)?
sbnCornUR:
sbnCornDR;
else
_DispBuf[lpNode->y][lpNode->x]=sbnVert;
}
lpNode=lpNode->Next;
}
}
}
voidTSnakeBuf:
:
InitStage(intStgNum)
{
_iBeanNo=0;
_bGameOver=false;
_bEndStage=false;
memset(_Units,0,sizeof(_Units));
memset(_DispBuf,0,sizeof(_DispBuf));
GenWalls(StgNum);
InitSnake();
DrawSnake();
GenBean();
}
voidTSnakeBuf:
:
ClearScore(void)
{
_iScore=0;
}