




已阅读5页,还剩21页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
课程名称可视化编程(VC)学 院计算机科学与技术学院专 业软件工程专业班 级姓 名指导教师20122013学年 第2学期目录1、 课程设计要求- 22、 系统功能实现与操作- 23、 系统设计概述- 23.1添加结构体说明- 23.2模块说明- 33.3主要功能函数代码及注释- 34、调试过程-114.1添加功能说明- 114.2错误及解决方案- 115、 程序运行结果- 12附:主要类Cview的成员函数代码-151、课程设计要求题目:基于MFC的贪吃蛇游戏设计与实现。要求:1.游戏界面设计 2.食物的初始化 3.游戏开始以及具体实现2、系统功能实现与操作本系统运用API函数的相关功能进行界面设计和功能实现。通过Rectangle()函数绘制操作区域及障碍物。通过连续的小矩形实现蛇身的绘制。通过srand()函数和rand()函数生成随机数,完成生成食物功能的实现。综合运用多种if条件判断和for循环的嵌套使用的算法完成各种条件判断。 该系统功能简单,操作简易。打开程序后,点击菜单栏的游戏按钮,点击开始游戏,系统弹出对话框,提示还有3秒开始。游戏开始后,贪吃蛇开始移动,通过操作键盘上的上下左右方向键控制蛇的移动,躲避障碍物并吃掉食物。当吃掉的食物累计到达一定数量后,蛇行速度加快。直至撞到边界或障碍物或撞到自身,游戏结束。此时弹出对话框,提示所得分数。游戏中途可通过暂停和继续按钮执行相应操作。3、 系统设计概述3.1 添加结构体说明struct Snakeint x,y;int len;int direct;Snake50;struct Foodint x;int y;int food;Food;Snake结构体数组用于存放贪吃蛇的相关数据,其中x,y存放当前节点矩形左上角的坐标,(Snake0为蛇头),len存放当前蛇身的长度,direct存放蛇的行进方向,可在14取值。Food结构体用于存放食物的位置信息。其中x,y存放食物小矩形左上角左标,food存放食物存在的布尔判断值。3.2 模块说明系统代码部分主要分为三个模块,界面控制模块、初始化模块和功能模块。界面控制模块包括函数:OnStart(),OnPause(),OnContinue(),OnExit()初始化模块包括函数:OnInitialUpdate(),OnDraw(),oninit()功能模块包括函数:OnKeyDown(),OnTimer()3.3 主要功能函数代码及注释OnStart()void CSnakeView:OnStart() / TODO: Add your command handler code hereSetTimer(1,3000,NULL);AfxMessageBox(还有3秒开始!);点击开始游戏触发,设置定时器控制三秒后开始游戏。OnPause()void CSnakeView:OnPause() / TODO: Add your command handler code hereKillTimer(1);AfxMessageBox(不要让人家等太久);关闭定时器,暂停游戏OnContinue()void CSnakeView:OnContinue() / TODO: Add your command handler code hereSetTimer(1,10,NULL);重启定时器,恢复游戏OnExit()void CSnakeView:OnExit() / TODO: Add your command handler code hereAfxMessageBox(欢迎下次再来!);exit(0);弹出对话框提示退出。OnInitialUpdate()void CSnakeView:OnInitialUpdate() CView:OnInitialUpdate();/ TODO: Add your specialized code here and/or call the base classSnake0.x=10;Snake0.y=10;Snake1.x=10;Snake1.y=10;Snake2.x=10;Snake2.y=10;Snake0.direct=2;Snake0.len=3;Food.food=1;/初始化蛇的长度和位置 用这个函数进行蛇的初始化工作。初始化贪吃蛇起初有3个节点,长度为3,起始坐标存入数组,食物为1无0有。OnDraw()void CSnakeView:OnDraw(CDC* pDC)CSnakeDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data hereCBrush backBrush(RGB(111,111,111);CBrush* pOldBrush = pDC-SelectObject(&backBrush);CRect rect;pDC-GetClipBox(&rect);pDC-PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);pDC-SelectObject(pOldBrush);pDC-Rectangle(9,9,401,401);CBrush zaBrush(RGB(111,111,111);pDC-SelectObject(zaBrush);for(int m=0;mRectangle(150,(100+m*10),160,(110+m*10);for(int n=0;nRectangle(250+n*10),200,(260+n*10),210);oninit();窗口创建时架构调用的函数,通过此函数完成界面初始化。创建灰色画刷选入设备环境,通过绘图函数绘制用户区。用两个for循环逐次绘制矩形的算法绘制出场景中的障碍物。oninit()void CSnakeView:oninit()CDC *pDC=GetDC();CBrush DrawBrush=(RGB(255,0,0);CBrush *Drawbrush=pDC-SelectObject(&DrawBrush);for(int i=0;iRectangle(Snakei.x*10,Snakei.y*10,(Snakei.x+1)*10,(Snakei.y+1)*10);pDC-SelectObject(DrawBrush);/利用for循环绘制起始的蛇身 该函数为自己添加的成员函数,用于绘制开始时的蛇身(长度为3)。OnKeyDown()void CSnakeView:OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) / TODO: Add your message handler code here and/or call defaultswitch(nChar)case VK_UP:if(Snake0.direct!=2) Snake0.direct=1;break;case VK_DOWN:if(Snake0.direct!=1) Snake0.direct=2;break;case VK_LEFT:if(Snake0.direct!=4) Snake0.direct=3;break;case VK_RIGHT:if(Snake0.direct!=3) Snake0.direct=4;break;/通过键盘设置转头方向CView:OnKeyDown(nChar,nRepCnt,nFlags);CView:OnKeyDown(nChar,nRepCnt,nFlags);该函数为键盘消息的接收函数。从键盘得到的上下左右的不同按键,会根据switch判断语句的case改变Snake。direct的值,从而改变蛇的行进方向。OnTimer()void CSnakeView:OnTimer(UINT nIDEvent) / TODO: Add your message handler code here and/or call defaultCDC *pDC=GetDC();CString soure;int j=0;if(Snake0.len=3)SetTimer(1,170,NULL);if(Snake0.len=9)SetTimer(1,130,NULL);if(Snake0.len=14)SetTimer(1,95,NULL);if(Snake0.len=18)SetTimer(1,60,NULL);/根据蛇的长度进行速度的设定soure.Format(得分:%d!,(Snake0.len-3)*10); /设置每个食物100分/撞墙判断if(Snake0.direct=3)&Snake0.x*10=17|(Snake0.direct=1)&Snake0.y*10=382|(Snake0.direct=2)&Snake0.y*10=382)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/分四种情况撞障碍判断,k为循环控制标识-if(Snake0.direct=3)for(int k=0;k20;k+)if(Snake0.x*10=160&Snake0.y*10=(100+k*10) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=350&Snake0.y*10=200)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=2)for(int k=0;k10;k+)if(Snake0.x*10=(250+k*10)&Snake0.y*10=200) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=150&Snake0.y*10=90)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=1)for(int k=0;k10;k+)if(Snake0.x*10=(250+k*10)&Snake0.y*10=210) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=150&Snake0.y*10=300)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=4)for(int k=0;k3)for(int sn=Snake0.len-1;sn0;sn-)if(Snake0.x*10=Snakesn.x*10&Snake0.y*10=Snakesn.y*10)j=1;KillTimer(1);AfxMessageBox(soure);/对尾节点用白笔涂掉if(j!=1)pDC-SelectStockObject(WHITE_PEN);pDC-Rectangle(SnakeSnake0.len-1.x*10,SnakeSnake0.len-1.y*10,(SnakeSnake0.len-1.x+1)*10,(SnakeSnake0.len-1.y+1)*10);for(int i=Snake0.len-1;i0;i-)Snakei.x=Snakei-1.x;Snakei.y=Snakei-1.y;/行走方向判断if(Snake0.direct=1)Snake0.y-;if(Snake0.direct=2)Snake0.y+;if(Snake0.direct=3)Snake0.x-;if(Snake0.direct=4)Snake0.x+;pDC-SelectStockObject(BLACK_PEN);CBrush DrawBrush=(RGB(255,0,0);CBrush *Drawbrush=pDC-SelectObject(&DrawBrush);if(j!=1) pDC-Rectangle(Snake0.x*10,Snake0.y*10,(Snake0.x+1)*10,(Snake0.y+1)*10);pDC-SelectObject(DrawBrush);/判断吃食物的条件if(Snake0.x*10=Food.x*10&Snake0.y*10=Food.y*10)Snake0.len+;Food.food=1;SnakeSnake0.len-1.x=SnakeSnake0.len-2.x;SnakeSnake0.len-1.y=SnakeSnake0.len-2.y;/生成食物int o=1;/控制生成食物成功时跳出循环if(Food.food=1) srand(unsigned)time(NULL); do Food.x=rand()%40; Food.y=rand()%40; if(Food.x!=0&Food.y!=0) /不能再区域外或障碍物中生成食物 for(int p=0;p20;p+) if(Food.x*10!=150&Food.y!=(100+p*10) o=0; if(o!=1) for(int q=0;qRectangle(Food.x*10,Food.y*10,(Food.x+1)*10,(Food.y+1)*10); Food.food=0; CView:OnTimer(nIDEvent);主要功能函数,响应于定时器消息,用于实时改变游戏界面,是游戏功能实现的主要函数。下面依次解释其中功能模块:1、 用四个if判断语句对蛇身长度进行判断,然后设置定时器间隔控制蛇行速度。2、 对撞墙进行判断,当蛇头的坐标企图越过系统边界并且其行进方向是冲着墙的方向时,判定撞墙,关闭定时器并且置程序结束标志j=1。3、 撞障碍物判断,同撞墙判断,对蛇的行进方向分上下左右四种情况进行判断,然后判断蛇头坐标是否企图越过障碍物。若撞届则同样置程序结束标志j=1。4、 撞蛇身判断,此算法是if嵌套for循环嵌套if判断,对蛇头的坐标和舍身每一点的坐标进行一次比较,看是否有蛇头的坐标与蛇身坐标重合。若有则判定自撞,置程序结束标志j=1。5、 蛇行进的实现。蛇行进主要的算法是,每一次Timer消息,将蛇的蛇头的下一位置添加一个矩形,并且将蛇尾的小矩形用与背景相同颜色的矩形填充掉,完成删除。通过一个for循环来实现。6、 行走方向判断,通过对Snake.direct进行判断,控制蛇头坐标在x,y方向上自加或自减,完成方向的设定。7、 判断吃食物的条件,若蛇头坐标与食物坐标重合,则吃食物。置食物标识为1表示没有食物。8、 生成食物方法。通过rand()函数产生随机数,通过计算得到相应食物的坐标。对该坐标的可行性进行判断,若坐标在操作区外或在障碍物中,则舍弃,循环执行这一步知道得到可行坐标,绘制食物矩形。4、 调试过程4.1 添加功能说明在此软件完成后,仅能实现定速度的无障碍的贪吃蛇游戏。经过改进,添加了初始化的相应代码,修改了Timer()函数的相关功能代码,实现了速度根据食物个数可变,添加了障碍物。4.2 错误及解决方案在编写程序的过程中遇到了诸多错误,除书写错误外,其他错误通过探讨和查阅资料的方式得到解决。具体问题有以下几个:之前对MFC图形的相关类了解的比较少,仔细看书后学习了CDC类的相关知识,了解了在NFC编程中图形函数的使用方法。在遍写程序之前,不清楚在单文档MFC程序中,架构对各个类的功能函数的调用次序,所以不知道应该将初始化的相关内容写在哪一个函数中,经查阅资料得知,OnInitialUpdate是视图窗口完全建立后第一个被框架调用的函数。框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。在时间上,两者先后顺序不同,构造函数生成本类的对象,但没有产生窗口,OnCreate后窗口产生,然后才是视图的OnInitialUpDate,一般在这里对视图的显示做初始化。在运行程序后,出现BUG,当蛇行至靠近障碍物或墙壁那一列时就判定了撞墙,导致蛇没有办法沿着游戏区域的边界行走,吃不到边上的食物。仔细研究代码后,在撞界判断中对蛇头坐标的基础上加入了对蛇行方向的判断,解决了这一问题。在撞界结束游戏后,蛇仍然会向前走一步,走到边界的外面。仔细研究代码后没有发现错误,和同学探讨后发现,在OnTimer()函数中,撞界后则弹出对话框,终止计时器,但程序还会将此函数执行完,所以蛇还会向前走一步。于是在撞界判断中加入了程序结束标志,在撞界后立即结束程序不再执行任何语句。解决了这一问题。在添加了障碍物之后食物生成在“墙”里。于是在生成随机数的判定中,加入了对生成坐标在墙内的判断,解决了这一问题。在程序完成后,我还想完成脱机运行的功能,即在没有VC的计算机上也能够运行这个程序。上网查阅了相关资料,了解到:在编写MFC程序时,对基类的连接有静态和动态两种。当选择静态连接时,系统会在编译组建时将用到的类封装在程序中,就能够离开编程环境运行了。也就是MFC的EXE可执行文件分为Debug版和Release版。于是这个问题也得到了解决。最终,在不懈的努力下,程序终于得以完美运行了5、 程序运行结果附:主要类Cview的成员函数代码/ snakeView.cpp : implementation of the CSnakeView class/#include stdafx.h#include snake.h#include snakeDoc.h#include snakeView.h#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE = _FILE_;#endifstruct Snakeint x,y;int len;int direct;Snake50;struct Foodint x;int y;int food;Food;/ CSnakeViewIMPLEMENT_DYNCREATE(CSnakeView, CView)BEGIN_MESSAGE_MAP(CSnakeView, CView)/AFX_MSG_MAP(CSnakeView)ON_WM_KEYDOWN()ON_WM_TIMER()ON_COMMAND(ID_START, OnStart)ON_COMMAND(ID_PAUSE, OnPause)ON_COMMAND(ID_EXIT, OnExit)ON_COMMAND(ID_CONTINUE, OnContinue)/AFX_MSG_MAP/ Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView:OnFilePrintPreview)END_MESSAGE_MAP()/ CSnakeView construction/destructionCSnakeView:CSnakeView()/ TODO: add construction code hereCSnakeView:CSnakeView()BOOL CSnakeView:PreCreateWindow(CREATESTRUCT& cs)/ TODO: Modify the Window class or styles here by modifying/ the CREATESTRUCT csreturn CView:PreCreateWindow(cs);/ CSnakeView drawingvoid CSnakeView:OnDraw(CDC* pDC)CSnakeDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data hereCBrush backBrush(RGB(111,111,111);CBrush* pOldBrush = pDC-SelectObject(&backBrush);CRect rect;pDC-GetClipBox(&rect);pDC-PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);pDC-SelectObject(pOldBrush);pDC-Rectangle(9,9,401,401);CBrush zaBrush(RGB(111,111,111);pDC-SelectObject(zaBrush);/绘制障碍物for(int m=0;mRectangle(150,(100+m*10),160,(110+m*10);for(int n=0;nRectangle(250+n*10),200,(260+n*10),210);oninit();/ CSnakeView printingBOOL CSnakeView:OnPreparePrinting(CPrintInfo* pInfo)/ default preparationreturn DoPreparePrinting(pInfo);void CSnakeView:OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: add extra initialization before printingvoid CSnakeView:OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: add cleanup after printing/ CSnakeView diagnostics#ifdef _DEBUGvoid CSnakeView:AssertValid() constCView:AssertValid();void CSnakeView:Dump(CDumpContext& dc) constCView:Dump(dc);CSnakeDoc* CSnakeView:GetDocument() / non-debug version is inlineASSERT(m_pDocument-IsKindOf(RUNTIME_CLASS(CSnakeDoc);return (CSnakeDoc*)m_pDocument;#endif /_DEBUG/ CSnakeView message handlersvoid CSnakeView:OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) / TODO: Add your message handler code here and/or call defaultswitch(nChar)case VK_UP:if(Snake0.direct!=2) Snake0.direct=1;break;case VK_DOWN:if(Snake0.direct!=1) Snake0.direct=2;break;case VK_LEFT:if(Snake0.direct!=4) Snake0.direct=3;break;case VK_RIGHT:if(Snake0.direct!=3) Snake0.direct=4;break;/通过键盘设置转头方向CView:OnKeyDown(nChar,nRepCnt,nFlags);CView:OnKeyDown(nChar,nRepCnt,nFlags);void CSnakeView:OnTimer(UINT nIDEvent) / TODO: Add your message handler code here and/or call defaultCDC *pDC=GetDC();CString soure;int j=0;if(Snake0.len=3)SetTimer(1,170,NULL);if(Snake0.len=9)SetTimer(1,130,NULL);if(Snake0.len=14)SetTimer(1,95,NULL);if(Snake0.len=18)SetTimer(1,60,NULL);/根据蛇的长度进行速度的设定soure.Format(得分:%d!,(Snake0.len-3)*10); /设置每个食物100分/撞墙判断if(Snake0.direct=3)&Snake0.x*10=17|(Snake0.direct=1)&Snake0.y*10=382|(Snake0.direct=2)&Snake0.y*10=382)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/分四种情况撞障碍判断,k为循环控制标识-if(Snake0.direct=3)for(int k=0;k20;k+)if(Snake0.x*10=160&Snake0.y*10=(100+k*10) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=350&Snake0.y*10=200)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=2)for(int k=0;k10;k+)if(Snake0.x*10=(250+k*10)&Snake0.y*10=200) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=150&Snake0.y*10=90)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=1)for(int k=0;k10;k+)if(Snake0.x*10=(250+k*10)&Snake0.y*10=210) j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);if(Snake0.x*10=150&Snake0.y*10=300)j=1;/用来控制直接结束当前函数KillTimer(1);AfxMessageBox(soure);/-if(Snake0.direct=4)for(int k=0;k3)for(int sn=Snake0.len-1;sn0;sn-)if(Snake0.x*10=Snakesn.x*10&Snake0.y*10=Snakesn.y*10)j=1;KillTimer(1);AfxMessageBox(soure);/对尾节点用白笔涂掉if(j!=1)pDC-SelectStockObject(WHITE_PEN);pDC-Rectangle(SnakeSnake0.len-1.x*10,SnakeSnake0.len-1.y*10,(SnakeSnake0.len-1.x+1)*10,(SnakeSnake0.len-1.y+1)*10);for(int i=Snake0.len-1;i0;i-)Snakei.x=Snakei-1.x;Snakei.y=Snakei-1.y;/行走方向判断if(Snake0.direct=1)Snake0.y-;if(Snake0.direct=2)Snake0.y+;if(Snake0.direct=3)Snake0.x-;if(Snake0.direct=4)Snake0.x+;pDC-SelectStockObject(BLACK_PEN);CBrush DrawBrush=(RGB(255,0,0);CBrush *Drawbrush=pDC-SelectObject(&DrawBrush);if(j!=1) pDC-Rectangle(Snake0.x*10,Snake0.y*10,(Snake0.x+1)*10,(Snake0.y+1)*10);pDC-SelectObject(DrawBrush);/判断吃食物的条件if(Snake0.x*10=Food.x*10&Snake0.y*10=Food
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年国际美术设计师考试基础内容及答案
- 篮球模拟测试题及答案
- 助理广告师试题及答案知识架构
- 2024年助理广告师备考心得与实战经验分享试题及答案
- 植物辨识考试题及答案
- 2024年国际设计师考试的综合准备建议试题及答案
- 于设计教育中的广告设计课程建设探讨试题及答案
- 新材料在纺织品设计中的应用举例试题及答案
- 小升初舞蹈测试题及答案
- 北大竞赛数学试题及答案
- 2025年房地产顾问合同8篇
- DB3208T 213-2024国有资产管理工作规范
- 2025北京九年级(上)期末语文汇编:句子默写
- 2025-2030中国浆果行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国网络贷款(融资)行业市场发展现状及发展趋势与投资研究报告
- 基建招聘面试题及答案
- 华为测试面试题及答案
- 漂珠销售合同协议
- 2025化学中考解题技巧 专题10 技巧性计算(解析版)
- 部门加班调休管理制度
- 考勤制度操作指南
评论
0/150
提交评论