C++贪吃蛇课程设计Word文档格式.docx
- 文档编号:18121384
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:18
- 大小:122.28KB
C++贪吃蛇课程设计Word文档格式.docx
《C++贪吃蛇课程设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《C++贪吃蛇课程设计Word文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
现在的贪吃蛇游戏一般是用C语言实现的,用C语言编写贪吃蛇游戏比较简单易懂,当然也可以用其他语言来实现,比如Java、C++、C#等,这里我们用C++来实现。
2、用C++的优势
C++在一定程度上可以和C语言很好的结合,甚至大多数C语言程序是在C++的集成开发环境中完成的。
C++相对众多的面向对象的语言,具有相当高的性能。
C++引入了面向对象的概念,使得开发人机交互类型的应用程序更为简单、快捷。
很多优秀的程序框架包括Boost、Qt、MFC、OWL、WTL就是使用的C++。
人们一般认为,使用Java或C#的开发成本比C++低。
但是,如果充分分析C++和这些语言的差别,会发现这句话的成立是有条件的。
这个条件就是:
软件规模和复杂度都比较小。
如果不超过3万行有效代码(不包括生成器产生的代码),这句话基本上还能成立。
否则,随着代码量和复杂度的增加,C++的优势将会越来越明显。
造成这种差别的就是C++的软件工程性。
相对于其他的语言,C++具有它自己的优势,主要体现在以下几个方面:
(1)、C++实现了面向对象程序设计。
在高级语言当中,处理运行速度是最快的,大部分的游戏软件,系统都是由C++来编写的。
(2)、C++语言非常灵活,功能非常强大。
如果说C语言的优点是指针,那么C++的优点就是性能和类层次结构的设计。
(3)、C++非常严谨、精确和数理化,标准定义很细致。
(4)、C++语言的语法思路层次分明、相呼应;
语法结构是显式的、明确的。
当然,这只是C++的一部分优势,在运用过程中,我们会逐渐发现C++语言之美。
3、实现的功能
⑴运行程序。
⑵点击“游戏->
开始”,出现围墙界面,一条蛇在密闭的围墙内,在围墙内随机出现一食物,游戏开始。
⑶游戏开始后,通过四个方向键控制蛇的运动方向,吃掉随机出现的豆子,若不小心碰到墙壁或者与自身相交,则该轮游戏结束。
⑷游戏结束后,会弹出游戏得分。
⑸点击“游戏->
暂停”,暂停游戏。
⑹点击“游戏->
继续”,继续游戏。
⑺游戏会根据蛇身的长度自动调节难易程度。
⑻点击“游戏->
退出”,退出游戏。
⑼单击帮助->
游戏规则查看游戏规则。
4、主要的思想
1定义蛇和食物的全局变量,初始化贪吃蛇各项成员变量,包括图像的出现在屏幕的初始位置,长度,以及蛇的行走方向。
食物类的定义包括出现的初始位置,以及食物是否被吃掉的判断。
2用数组初始化长度为3的贪吃蛇,并且默认食物未出现
3在CView类上运用MFC提供的Windows消息中WM_TIMER消息,运用OnTimer()函数让系统提供一个时钟节拍,更新游戏
4具体游戏实现,包括蛇撞到自己和围墙都将使游戏结束,判断吃豆等,其中还包括根据蛇的长度来进行游戏难度的改变。
5具体键盘游戏操作运用到Windows消息响应中的WM_KEYDOWN,用OnKeyDown()来响应玩家的实际操作
4、游戏界面如下:
图1游戏界面
图1
二、概要设计
1、首先,用一个结构体数组来标记蛇的X位置和Y位置,还有每一节的方向。
用一变量标识蛇的长度。
2、在蛇非转弯的移动时用定时器来自动移动,不管蛇是哪种形状,都只需在每次移动时先将各节向后移动(蛇尾舍弃,新的蛇尾由蛇尾的上一节代替):
如蛇本身为snake[0]到snake[3],就是将snake[0]到snake[2]一起移动到snake[1]到snake[3]:
将snake[2]的XY坐标赋值snake[3]的XY坐标,snake[1]的XY坐标赋值给snake[2]的XY坐标,snake[0]的XY坐标赋值给snake[1]的XY坐标。
再判断蛇头的方向,然后将蛇头顺着这个方向向前移动一格就是蛇头snake[0]的XY坐标。
而蛇除蛇头外各节的方向由函数SetDirection()来确定(明显此种情况,蛇头的方向不变),SetDirection()的思想是根据蛇的每一节的前一节的相对位置来确定本节的方向。
(其实这个函数是多余的,真正用到的只有蛇头的方向)。
3、蛇在转弯时,也是各节一次向后移,蛇头的位置顺着转弯的方向移动,方向由转弯方向确定。
4、蛇在吃到食物时,长度加一,蛇头的位置变成食物的位置,方向不变。
蛇的本身每节的XY位置都向后移。
如蛇本身为snake[0]到snake[3],就是将snake[0]到snake[3]一起移动到snake[1]到snake[4]。
5、具体键盘游戏操作运用到Windows消息响应中的WM_KEYDOWN,用OnKeyDown()来响应玩家的实际操作。
6、每次蛇在转弯时只能有一种方向按键能响应,即要么左右转,要么上下转。
蛇头方向向左或向右时,只能上下转;
蛇头方向向上或向下时,只能左右转。
7、食物的位置由rand函数随机产生。
游戏运行界面如图2所示:
图2游戏界面
8、游戏框架如下:
图3游戏框架
3、主要类及成员函数、数据成员的说明如表1所示
表1
类的名称
成员名称
功能
Snake
x
蛇的横坐标
y
蛇的纵坐标
len
蛇的长度
direct
指引蛇的方向
Food
食物的横坐标
食物的纵坐标
sfood
食物个数
CSnakeView
OnStart()
控制游戏开始
OnPause()
控制游戏暂停
OnContinue()
控制游戏继续
OnExit()
控制游戏退出
OnKeyDown()
接收用户键入的信息,然后用switch进行选择判断
OnRButtonDown()
用鼠标右键屏幕,就会马上显示当前位置的坐标信息
该函数画一个矩形,用当前的画笔画矩形轮廓,用当前画刷进行填充
oninit()
OnTime()
改变蛇的移动速度,判断蛇是否撞墙,食物的随机分配,吃食物以后长度的增加,蛇的移动方向的改变
OnDraw(CDC*pDC)
用画刷画一个背景,并且包含当前可见区域的最小矩形的大小,使用当前选入指定设备环境中的刷子绘制给定的矩形区域
三、详细设计
1、添加消息处理函数
在已有工程下的ClassView中右键Cview类添加以下Windows信息
WM_RBUTTONDOWN
WM_TIMER
再右键CView类选择“ADDVirtualFunciton”选OnInitialUpdate()
OnInitialUpdate()的功能如下:
视图窗口完全建立后第一个被框架调用的函数。
框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。
时间上,两者先后顺序不同,构造函数生成本类的对象,但没有产生窗口,OnCreate后窗口产生,然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化。
简单点,就是ONCREATE只是产生VIEW的基本结构和变量而在OnInitialUpDate()中,主要初始化视图中控件等。
所以我们要用这个函数来进行贪吃蛇的初始化工作。
再者还要添加一个成员函数oninit()进行贪吃蛇外观的初始化。
2、控件的设计
再者是设计游戏的一些控件来控制“游戏开始”“游戏结束”和“游戏暂停”。
我们可以点击“工作空间”的“ResourceView”进行控件的具体设计,这里我们在Menu文件夹中把“IDR_MAINFRAME”中默认的控件全部删除,右键其中的标题栏,点击属性,会得到一个菜单栏标题,我们分别建立1个菜单栏标题。
这里我们分别建“游戏”。
图4添加的控件
点击并且在已有控件中的列表中点击属性,进行“菜单项目属性”的设置。
我们本别建立的属性“标明”与对应的ID有
游戏开始IDM_START
游戏暂停IDM_PAUSE
游戏继续IDM_CONTINUE
游戏退出IDM_EXIT
成功设置ID之后我们分别右键各项属性进行消息响应处理函数的生成
具体方法操作例子如下
1右键“游戏开始”
2点击“类向导建立”
3在MessageMaps页面,在要进行消息响应的控件ID列表ObjectIDs中上选择对应的ID,这里我们选择IDM_START,具体实现的环境是CView类,所以我们必须把“Classname”的默认“CMainFrame”改为“CView类”,并且在“Messages”类型设置中,用“COMMAND”设置为其为命令消息。
其余各项也按照同理进行设置。
3、具体实现游戏
Step1
首先我们在文件开头处分别定义蛇和食物的全局变量
staticstructSnake
{
intx,y;
intlen;
intdirect;
}Snake[1000];
staticstructFood
intx;
inty;
intisfood;
}Food;
再者初始化贪吃蛇
voidCSnakeView:
:
OnInitialUpdate()
CView:
OnInitialUpdate();
Snake[0].x=10;
Snake[0].y=10;
Snake[1].x=11;
Snake[1].y=10;
Snake[2].x=12;
Snake[2].y=10;
Snake[0].direct=3;
Snake[0].len=3;
Food.isfood=1;
}
初始化贪吃蛇起初有3个节点,长度为3和起始坐标;
食物默认为1无0有。
Step2对OnKeyDown()具体添加代码
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)
switch(nChar)
{
caseVK_UP:
if(Snake[0].direct!
=2)Snake[0].direct=1;
break;
caseVK_DOWN:
=1)Snake[0].direct=2;
caseVK_LEFT:
=4)Snake[0].direct=3;
caseVK_RIGHT:
=3)Snake[0].direct=4;
}
OnKeyDown(nChar,nRepCnt,nFlags);
代码说明:
Snake[0]代表的是蛇头,我们对蛇头的方向Snake[0].direct进行判断。
caseVK_UP:
意思就是当Snake[0].direct的方向此时并不等于“下”的时候,才能做出“上”的操作动作,否则则忽略用户“向上”的操作按键效果。
OnKeyDown函数的第一个参数UINTnChar是接收用户键入的信息,然后我们用switch进行选择判断。
Step3对OnRButtonDown()具体添加代码
OnRButtonDown(UINTnFlags,CPointpoint)
CStringstr;
str.Format("
%d,%d"
point.x,point.y);
AfxMessageBox(str);
OnRButtonDown(nFlags,point);
这个函数功能是:
用鼠标右键屏幕,就会马上显示当前位置的坐标信息。
Step4
CDC*pDC=GetDC();
CBrushDrawBrush=(RGB(100,100,100));
CBrush*Drawbrush=pDC->
SelectObject(&
DrawBrush);
for(inti=0;
i<
=Snake[0].len-1;
i++)
pDC->
Rectangle(Snake[i].x*20,Snake[i].y*20,(Snake[i].x+1)*20,(Snake[i].y+1)*20);
SelectObject(DrawBrush);
利用Windows给我们提供的CDC类来进行画图,我们首先用一个指向CDC类的指针去接受与该窗口相关联的DC句柄,然后用定义画刷一个DrawBrush对象,并且用RGB(100,100,100)来给画刷初始化颜色。
并且用SelectObject(&
函数把对象画刷选入到设备描述表中,用for循环依次把贪吃蛇的3个节点画出来。
Step5控件添加代码
OnStart()
SetTimer(1,1000,NULL);
OnInitialUpdate();
OnPause()
KillTimer
(1);
AfxMessageBox("
暂停游戏..."
);
OnExit()
退出游戏..."
exit(0);
OnContinue()
SetTimer(1,10,NULL);
由于之前我们设定了WM_TIMER消息,我们能运用计时器功能。
用WM_TIMER来设置定时器
先请看SetTimer这个API函数的原型
UINT_PTRSetTimer(
HWNDhWnd,//窗口句柄
UINT_PTRnIDEvent,//定时器ID,多个定时器时,可以通过该ID判断是哪个定时器
UINTuElapse,//时间间隔,单位为毫秒
TIMERPROClpTimerFunc//回调函数
);
SetTimer(m_hWnd,1,1000,NULL);
//一个1秒触发一次的定时器
在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了,所以我们这里可以只去后3个参数写成SetTimer(1,10,NULL);
,1000为1秒。
Step6对OnDraw()的添加代码
CSnakeDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CBrushbackBrush(RGB(100,0,100));
CBrush*pOldBrush=pDC->
backBrush);
CRectrect;
pDC->
GetClipBox(&
rect);
PatBlt(rect.left,rect.top,rect.Width(),rect.Height(),PATCOPY);
SelectObject(pOldBrush);
Rectangle(19,19,501,501);
oninit();
此处是用画刷画一个背景,并且画出3个矩形区域
函数原型:
intGetClipBox(HDChdc,LPRECTlprc);
该函数得到一个能够完包含当前可见区域的最小矩形的大小。
intnYLeft,intnWidth,intnHeight,DWORDdwRop);
该函数使用当前选入指定设备环境中的刷子绘制给定的矩形区域。
Step7对OnTime()的添加代码
由于该函数代码部分太复杂我们将其分开逐一分析:
OnTimer(UINTnIDEvent)
CStringsoure;
SetTimer(1,360-Snake[0].len*10,NULL);
soure.Format("
得分:
%d!
"
(Snake[0].len-3)*10);
if(Snake[0].x*20<
=37||Snake[0].y*20<
=37||Snake[0].x*20>
=462||Snake[0].y*20>
=462)
AfxMessageBox(soure);
这一部分是蛇身撞界判断。
蛇的一节身体为一个矩形块,这样表示每个矩形块只需起点坐标x和y身体是不断增长的,所以用数组存放每一节的坐标。
OnTimer(UINTnIDEvent)
{if(Snake[0].len>
3)
for(intsn=Snake[0].len-1;
sn>
0;
sn--)
if(Snake[0].x*20==Snake[sn].x*20&
&
Snake[0].y*20==Snake[sn].y*20)
KillTimer
(1);
AfxMessageBox(soure);
这一部分是蛇身相撞判断。
由于判断蛇自己是否咬到了自己,根据蛇长sn,进行sn次forsn-1次循环,并且和Snake[0].x进行比较(之所以进行sn-1次那肯定是不包括蛇头而且蛇的长度也必须大于3才会发生自己咬自己的情况)。
KillTimer
(1);
是停止计时器;
和之前的SetTime()对应而已。
AfxMessageBox(soure);
输出一个原样输出内容。
{if(Food.x==Snake[Snake[0].len-1].x&
Food.y==Snake[Snake[0].len-1].y)
else
{
SelectStockObject(WHITE_PEN);
Rectanglake[Snake[0].len-1].x*20,Snake[Snake[0].len-1].y*20,(Snake
[Snake[0].len-1].x+1)*20,(Snake[Snake[0].len-1].y+1)*20);
}
for(inti=Snake[0].len-1;
i>
i--)
Snake[i].x=Snake[i-1].x;
Snake[i].y=Snake[i-1].y;
是把白色的“PEN”选入设备进行画图
Rectangle(Snake[Snake[0].len-1].x*20,Snake[Snake[0].len-1].y*20,
(Snake[Snake[0].len-1].x+1)*20,(Snake[Snake[0].len-1].y+1)*20);
让它去画最后一个节点
for(inti=Snake[0].len-1;
i--)//贪吃蛇的蛇身移动
Snake[i].x=Snake[i-1].x;
Snake[i].y=Snake[i-1].y;
这里要要专门用白笔画最后一个,因为我们的游戏界面是用白色的,贪吃蛇移动的时候,肯定是蛇头向前走一单位,而尾部肯定要“擦除”掉一个单位,那怎么擦除呢?
我们只能用和背景色一样的画笔。
原来蛇的位置和新蛇的位置差一个单位,所以看起来蛇会多一节身体,所以将蛇的最后一节用背景色覆盖SelectStockObject(WHITE_PEN)让它起到“消失”最后一个节点的功能,让我们以为蛇是向前走了。
进行次数为"
长度-1"
次的循环
为什么要进行长度-1次呢?
我这里要说明一下,这里是不包括蛇头的进行的平移,用数组赋值的方法,把前一节点保存在后一个结点,然后头结点向前移动。
{if(Snake[0].direct==1)Snake[0].y--;
if(Snake[0].direct==2)Snake[0].y++;
if(Snake[0].direct==3)Snake[0].x--;
if(Snake[0].direct==4)Snake[0].x++;
SelectStockObject(BLACK_PEN);
Rectangle(Snake[0].x*20,Snake[0].y*20,(Snake[0].x+1)*20,(Snake[0].y+1)*
20);
这一部分是方向判断。
“1234”本别代表“上下左右”x++,y++进行移动,然后用选定画刷画出一个新节点的矩形作为头结点
{if(Snake[0].x*20==Food.x*20&
Snake[0].y*20==Food.y*20)
Snake[0].len++;
Food.isfood=1;
Snake[Snake[0].len-1].x=Snake[Snake[0].len-2].x;
Snake[Snake[0].len-1].y=Snake[Snake[0].len-2].y;
这一部分是判断吃豆的条件,撞到就吃。
{if(Food.isfood==1)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 贪吃 课程设计