基于MFC的贪吃蛇程序的设计报告课程设计Word文件下载.docx
《基于MFC的贪吃蛇程序的设计报告课程设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《基于MFC的贪吃蛇程序的设计报告课程设计Word文件下载.docx(21页珍藏版)》请在冰点文库上搜索。
4游戏开始后,界面右下角会同步游戏得分。
5通过四个方向键控制蛇的运动方向,吃掉随机出现的豆子,若不小心碰到墙壁或者与自身相交,则该轮游戏结束。
6点击“游戏->
游戏暂停”,暂停游戏。
7点击“游戏->
游戏继续”,继续游戏。
8游戏会根据蛇身的长度自动调节难易程度。
9点击“游戏->
游戏退出”,退出游戏。
10在界面中右键单击鼠标可以显示光标的当前坐标。
11单击帮助->
游戏规则查看游戏规则。
3 大体思想
1定义蛇类和食物类,初始化贪吃蛇各项成员变量,包括图像的出现在屏幕的初始位置,长度,以及蛇的行走方向。
食物类的定义包括出现的初始位置,以及食物是否被吃掉的判断。
2用数组初始化长度为3的贪吃蛇,并且默认食物未出现
3在CView类上运用MFC提供的Windows消息中WM_TIMER消息,运用OnTimer()函数让系统提供一个时钟节拍,更新游戏
4具体游戏实现,包括蛇撞到自己和围墙都将使游戏结束,判断吃豆等,其中还包括根据蛇的长度来进行游戏难度的改变。
5具体键盘游戏操作运用到Windows消息响应中的WM_KEYDOWN,用OnKeyDown()来响应玩家的实际操作。
6界面会自动最大化
7而且单击右键可以出现坐标
8添加了bmp格式的图片作为游戏背景。
4 程序框图
4.1 整体框架图
4.2 游戏控制模块框架图
5 主要知识点
1CView类中的消息响应
2控件的消息响应
3基于CView类内的具体游戏实现
4数组
5游戏图形的实现用CDC类实现
6SDI界面窗口样式的设计
7文本的显示
6 重要的MFC
1CWnd:
窗口,它是大多数“看得见的东西”的父类(Windows里几乎所有看得见的东西都是一个窗口,大窗口里有许多小窗口),比如视图CView、框架窗口CFrameWnd、工具条CToolBar、对话框CDialog、按钮CButton,etc;
一个例外是菜单(CMenu)不是从窗口派生的。
该类很大,一开始也不必学,知道就行了。
2CDocument文档,负责内存数据与磁盘的交互。
最重要的是OnOpenDocument(读入),OnSaveDocument(写盘),Serialize(读写)
3CView视图,负责内存数据与用户的交互。
包括数据的显示、用户操作的响应(如菜单的选取、鼠标的响应)。
最重要的是OnDraw(重画窗口),通常用CWnd:
:
Invalidate()来启动它。
另外,它通过消息映射表处理菜单、工具条、快捷键和其他用户消息。
你自己的许多功能都要加在里面,你打交道最多的就是它。
4CDC设备文本。
无论是显示器还是打印机,都是画图给用户看。
这图就抽象为CDC。
CDC与其他GDI(图形设备接口)一起,完成文字和图形、图像的显示工作。
把CDC想象成一张纸,每个窗口都有一个CDC相联系,负责画窗口。
CDC有个常用子类CClientDC(窗口客户区),画图通常通过CClientDC完成。
5CDialog对话框
6CWinApp应用程序类。
似于C中的main函数,是程序执行的入口和管理者,负责程序建立、消灭,主窗口和文档模板的建立。
最常用函数InitInstance():
初始化。
7CGdiObject及子类,用于向设备文本画图。
它们都需要在使用前选进DC
8CPen笔,画线
9CBrush刷子,填充
10CFont字体,控制文字输出的字体
11CBitmap位图
12CPalette调色板
13CRgn区域,指定一块区域可以用于做特殊处理。
14CFile文件。
最重要的不外是Open(打开),Read(读入),Write
15CString字符串。
封装了C中的字符数组,非常实用。
16CPoint点,就是(x,y)
CRect矩形,就是(left,top,right,bottom)
7 数据结构
7.1 蛇的全局变量
structSnake
{
intx,y;
intlen;
intdirect;
}Snake[50];
7.2 食物的全局变量
structFood
intx;
inty;
intisfood;
}Food;
8 主要函数
1voidCMFCexp8_4View:
OnDraw(CDC*pDC)//显示背景图片
2voidCMFCexp8_4View:
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)//按照用户的按键来控制蛇的移动
3voidCMFCexp8_4View:
OnRButtonDown(UINTnFlags,CPointpoint)//用鼠标右键屏幕,就会马上显示当前位置的坐标信息
4voidCMFCexp8_4View:
OnTimer(UINTnIDEvent)//根据蛇的长度来进行SetTimer()函数的定义,可以根据长度来进行游戏难度的设定。
//撞界判断//蛇身相撞判断//抹掉蛇行走的痕迹//判断吃豆的条件,撞到就吃//如果食物被吃了就生成
5voidCMFCexp8_4View:
oninit()//进行贪吃蛇外观的初始化
6voidCMFCexp8_4View:
OnStart()//开始游戏
7voidCMFCexp8_4View:
OnPause()//游戏暂停
8voidCMFCexp8_4View:
OnContinue()//继续游戏
9voidCMFCexp8_4View:
OnExit()//退出游戏
10voidCMFCexp8_4View:
OnInitialUpdate()//初始化蛇的位置
11voidCMFCexp8_4View:
OnDrawNew()//第二层白色正方形背景以及右下角的文字
9 代码实现
9.1 添加Windows信息
⑴在已有工程下的“ClassView”中右键CView类添加以下Windows信息
1WM_KEYDOWN
2WM_RBUTTONDOWN
3WM_TIMER
⑵右键CView类选择“ADDVirtualFunciton”选OnInitialUpdate(),再者还要添加一个成员函数oninit()进行贪吃蛇外观的初始化
9.2 控件的设计
⑴我们可以点击“工作空间”的“ResourceView”进行控件的具体设计,设计游戏的一些控件来控制“游戏开始”“游戏结束”和“游戏暂停”。
⑵右键其中的标题栏,点击属性,会得到一个菜单栏标题,我们建立“游戏”菜单栏标题。
⑶点击并且在已有控件中的列表中点击属性,进行“菜单项目属性”的设置。
分别建立的属性“标明”与对应的ID有
游戏开始 IDM_START
游戏暂停 IDM_PAUSE
游戏继续 IDM_CONTINUE
游戏退出 IDM_EXIT
⑷成功设置ID之后,分别单击右键各项属性进行消息响应处理函数的生成,具体方法操作例子如下:
右键“游戏开始”》点击“类向导建立”》在MessageMaps页面,在要进行消息响应的控件ID列表ObjectIDs中上选择对应的ID,这里我们选择IDM_START,具体实现的环境是CView类,所以我们必须把“Classname”的默认“CMainFrame”改为“CView类”,并且在“Messages”类型设置中,用“COMMAND”设置为其为命令消息。
其余各项也按照同理进行设置。
9.3 具体实现游戏
9.3.1 在文件开头处分别定义蛇和食物的全局变量
//定义蛇的全局变量
//定义食物的全局变量
9.3.2 初始化蛇的位置
voidCMFCexp8_4View:
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;
//初始化贪吃蛇起初有3个节点,长度为3
Snake[0].len=3;
Food.isfood=1;
//食物默认为1无0有
}
OnInitialUpdate()的功能如下:
视图窗口完全建立后第一个被框架调用的函数。
框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。
时间上,两者先后顺序不同,构造函数生成本类的对象,但没有产生窗口,OnCreate后窗口产生,然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化。
简单点,就是ONCREATE只是产生VIEW的基本结构和变量而在OnInitialUpDate()中,主要初始化视图中控件等。
对各个变量进行初始化操作,所以我们要用这个函数来进行贪吃蛇的初始化工作。
9.3.3 对OnKeyDown()具体添加代码
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)
switch(nChar)
{
//Snake[0]代表的是蛇头,对蛇头的方向Snake[0].direct进行判断
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);
9.3.4 对OnRButtonDown()具体添加代码
OnRButtonDown(UINTnFlags,CPointpoint)
//这个函数功能是:
用鼠标右键屏幕,就会马上显示当前位置的坐标信息
CStringstr;
str.Format("
%d,%d"
point.x,point.y);
AfxMessageBox(str);
OnRButtonDown(nFlags,point);
代码说明:
这个函数并不是本游戏中必要添加的函数,只是为了在后面游戏页面的设计的时候可以用鼠标右键屏幕了解大概的屏幕坐标信息,才特地做的。
这个设备坐标系以用户区窗口左上角为(0,0)原点,X坐标向右为正,Y坐标向下为正。
9.3.5 对oninit()具体添加代码
//画一个矩形,用当前的画笔画矩形轮廓,用当前画刷进行填充
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);
pDC->
SelectObject(DrawBrush);
利用Windows给我们提供的CDC类来进行画图,我们首先用一个指向CDC类的指针去接受与该窗口相关联的DC句柄,然后用定义画刷一个DrawBrush对象,并且用RGB(100,100,100)来给画刷初始化颜色。
并且用SelectObject(&
函数把对象画刷选入到设备描述表中,用for循环依次把贪吃蛇的3个节点画出来。
oninit()
9.3.6 对控件添加具体代码
OnStart()
CMFCexp8_4View:
OnDrawNew();
SetTimer(1,3000,NULL);
//定时器。
3000是3000毫秒,即3秒
AfxMessageBox("
3秒后开始游戏!
"
);
OnPause()
KillTimer
(1);
暂停游戏..."
OnContinue()
SetTimer(1,10,NULL);
OnExit()
退出游戏..."
exit(0);
由于之前我们设定了WM_TIMER消息,我们能运用计时器功能。
用WM_TIMER来设置定时器,SetTimer(m_hWnd,1,1000,NULL)是一个1秒触发一次的定时器,在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了,所以我们这里可以只去后3个参数写成SetTimer(1,10,NULL);
其中1000为1秒。
9.3.7 对OnDraw()添加具体代码,实现出现背景图片
⑴在“Resource.h”中添加“#defineIDB_MY_BITMAP130”
⑵在“Res”中添加“qiche.bmp”
⑶在“MFCexp8—4.cpp”中添加“IDB_MY_BITMAPBITMAPDISCARDABLE"
res\\qiche.bmp"
”
⑷添加以下代码:
OnDraw(CDC*pDC)
//以res文件夹中的bmp格式图片为背景
CMFCexp8_4Doc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CDCMemDC;
MemDC.CreateCompatibleDC(NULL);
MemDC.SelectObject(pDoc->
m_Bitmap);
BitBlt(0,0,pDoc->
m_nWidth,pDoc->
m_nHeight,&
MemDC,0,0,SRCCOPY);
9.3.8 对OnDrawNew()添加具体代码
⑴在添加代码之前,在“MFCexp8_4View.h”中添加:
classCMFCexp8_4View:
publicCView
protected:
//createfromserializationonly
CMFCexp8_4View();
DECLARE_DYNCREATE(CMFCexp8_4View)
//Attributes
public:
CMFCexp8_4Doc*GetDocument();
CClientDC*myDC;
CClientDC*my2DC;
//Operations
……
⑵对“CClientDC*myDC”和“CClientDC*my2DC”建立类向导
intCMFCexp8_4View:
OnCreate(LPCREATESTRUCTlpCreateStruct)
if(CView:
OnCreate(lpCreateStruct)==-1)
return-1;
//TODO:
Addyourspecializedcreationcodehere
myDC=newCClientDC(this);
my2DC=newCClientDC(this);
return0;
⑶voidCMFCexp8_4View:
OnDrawNew()
RECTRect;
Rect.left=Rect.top=20;
Rect.right=Rect.bottom=500;
CBrushBrush(RGB(255,255,255));
myDC->
FillRect(&
Rect,&
Brush);
//画出第二层背景,一个白色正方形
my2DC->
SetBkColor(RGB(0,0,0));
SetTextColor(RGB(255,255,255));
TextOut(750,400,"
单击“游戏”,选择“开始游戏”"
SetTextColor(RGB(255,0,255));
TextOut(800,430,"
请不要咬到自己或撞到围墙!
//在界面右下角分别出现三行背景色为黑色的彩色文本
9.3.9 对OnTimer(UINTnIDEvent)添加具体代码
OnTimer(UINTnIDEvent)
CStringsoure;
if(Snake[0].len==2)SetTimer(1,370,NULL);
if(Snake[0].len==3)SetTimer(1,270,NULL);
if(Snake[0].len==6)SetTimer(1,200,NULL);
if(Snake[0].len==9)SetTimer(1,100,NULL);
//这段代码的作用是根据蛇的长度来进行SetTimer()函数的定义,可以根据长度来进行游戏难度的设定
//如上代码分别370ms270ms200ms100ms进行一次新的移动。
soure.Format("
当前得分:
%d!
(Snake[0].len-3)*10);
SetTextColor(RGB(0,255,0));
TextOut(800,460,soure);
//撞界判断
if(Snake[0].x*20<
=37||Snake[0].y*20<
=37||Snake[0].x*20>
=462||Snake[0].y*20>
=462)
KillTimer
(1);
AfxMessageBox(soure);
CMFCexp8_4View:
OnExit();
//蛇身相撞判断
if(Snake[0].len>
3)
for(intsn=Snake[0].len-1;
sn>
0;
sn--)
//根据蛇长sn,进行sn次forsn-1次循环,判断蛇自己是否咬到了自己
{
if(Snake[0].x*20==Snake[sn].x*20&
&
Snake[0].y*20==Snake[sn].y*20)
{
KillTimer
(1);
//止计时器,和之前的SetTimer()对应
AfxMessageBox(soure);
CMFCexp8_4View:
}
}
///////////////////////////////////////////////////////////////////////////
pDC->
SelectStockObject(WHITE_PEN);
//把白色的“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>
i--)
//贪吃蛇的蛇身移动
Snake[i].x=Snake[i-1].x;
Snake[i].y=Snake[i-1].y;