




已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
贪吃蛇完整设计过程和完整源代码 简介 一直在学VC编程,但是感觉自己的进步甚微,还是什么都不懂,还是什么都不会编,再加上身心不适,学习总是断断续续的。期中考试过后,放六天假,闲来无事,在网上看到了别人编的贪吃蛇游戏,自己下载两个源代码,一个界面做的太不人性化,感觉那蛇不像蛇,都是断断续续的小点,感觉不是很好;另一个是在TC中编的,好像现在很少有人用TC,我想大家都应该跟我一样,都是用VC,没办法,需要画图,这个程序在VC中没办法运行,一DEBUG错误连篇,看都不想看了。所以自己有了编写这个游戏的念头。首先自己看了看别人编写贪吃蛇的思路(其实这就是这个游戏的精髓,我很惭愧啊)。就是使用链表来实现的。-到这里,是不是很感慨我们学过的数据结构原来是这么有用途啊?链表?用链表就可以实现吗?-没错!就是用链表(队列)实现的,在这个游戏程序中除了画图,定时,产生随机数之外,那就是链表的创建,扫描,入队和出队了。如果你懂链表的这些基本的操作,那没问题,这个游戏程序编写出来是没有问题的。当然还是得知道点(一点点)WIN32(API,我是用API,没用MFC,相比较API开始比MFC好学些哦)应用程序的基本框架的基本知识。比方说某些消息,WM_CREATE , WM_PAINT , WM_CHAR , WM_TIMER ;HPEN (画笔), HBRUSH(画刷),HDC(设备上下文环境) ;某些设置画笔、画刷的函数:CreatePen() , SelectObject() ;获取DC的函数,在WM_PAINT中要使用:BeginPaint() . EndPaint() ,在其他地方就要使用GetDC() .ReleaseDC() ;设置定时器函数SetTimer() ,销毁定时器函数KillTimer() 。好了,这就是编写出此程序所需要的全部知识,下面的过程要看个人的逻辑思维能力,编程经验。经验丰富,逻辑缜密的走的弯子肯定要少很多,否则,那当然会走完一个又一个弯子之后.还得继续走弯子,不过肯定会做出来的,只要坚持!不过也不排除人品大爆发的,用不了多久就编出来了。不过还是强烈建议多走走弯子,只有经历过,你才知道某段代码为什么要那么编,不那么编会出现什么样的情况。嗯废话说完了,进入正题吧。首先看看我们这个程序的运行效果吧,很是简陋,但是麻雀虽小,五脏俱全啊。界面设计这个游戏,那第一步要思考的当然是如何将格子画出来了。我们先确定下每一个格子的大小吧。我这里的大小为16*16,总共有20行20列。先定义宏 #define RowOfFrame 20 #define ColumnOfFrame 20 #define Width 16 #define Height 20 字面意思已经很清楚了。您可能恍然大悟,画这格子不很简单吗!对!不就是画20条横线,20条竖线吗!查下MSDN ,MoveToEx()是用来设定起始点的,LineTo()是用来画起点到终点的线。当然画线是用画笔去画的。那得创建具有这些要求的画笔了。两句话就搞定了:HPEN hpen=CreatePen(PS_SOLID,1,RGB(255,0,0);SelectObject(hdc,hpen);接下来画20条横线20条竖线吧。这个就是Design()函数所完成的功能。当然这里需要给每个格子一个定位坐标 ,程序中已经默认使用了。也很简单,就是我们在脑子里面给它一个坐标系就行了。比方说(0,0)代表的是左上角第一个格子,而(19,19)代表的是右下角的格子。假如一个格子的坐标为(x ,y),那么这个格子的左上顶点的实际坐标是多少呢?能想出来吧,不行就在纸上画画,是(x*Width , y*Height)。 这个我们在后面产生随机数,记录蛇节点,食物的位置等的时候要用到的。看到这里想必敏感的人可能已经知道怎么画蛇了吧,不也是用画笔画线吗,只不过线粗点而已,是不是?画食物也是一样的道理,简单得来吧 具体的操作参考一下函数DrawSnake(),DrawFood()。到这里,游戏所涉及的画图的知识就这么多。相信你可以用画笔画线、画矩形了吧。这在这里就足够了。是不是很简单呢?的确,这游戏一点都不难,要不然我这个阿斗怎么就编出来了呢?Believe yourself! Lets continue.数据结构下面得说说所涉及到的链表这个数据结构了。我们这里的蛇是一个个连续的格子组合在一起的,我们只要定义一个结构体记录格子的位置,那么蛇就是这些结构体所组成的链表了。结构体定义如下:Struct Node Int x; Int y; Node * next;Struct snake Node * head; Node * tail; Int length;功能模块我们在初始的时候,规定蛇的长度是1,所在的位置是(0,0)格子中。这是Init()函数所完成的功能。先不管蛇每隔1秒钟就按照原来的方向向前移动一个格子,也不管蛇吃到食物后长度增壹。这些统统都先不管,因为我们有比这还迫切的任务需要解决,这个问题解决不了,前面两个问题是怎么也实现不好的。您知道是什么问题吗?想想自己是怎么玩贪吃蛇游戏的?啊上下左右控制蛇的运动方向啊!是吧。这里为了方便,我使用的不是箭头,而是w(上)、s(下)、a(左)、d(右),我现在需要完成的功能是:蛇的初始位置在(0,0)格子,初始的方向是右。我每按一次d(是小写的啊),蛇就向前移动一个格子,我不按d(也没按w、s、a 或者.你懂的)蛇就不动。这个问题的本质就是将先前的窗口内图形擦除,然后再重新绘制一幅图形(画格子,画食物,画蛇新的位置)。首先说将先前窗口内图形擦除掉的方法。也很简单,入门的都应该知道,我用背景色画一个窗口客户区那么大的矩形把它覆盖掉不就完事了吗!嗯至少我用的就是这个方法。同样也是几行代码而已:RECT rect;GetClientRect(hdc,&rect);SelectObject(hdc,(HBRUSH)GetStockObject(WHILE_BRUSH);Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);擦掉了吧?但是您肯定会说我只是想把蛇向前挪一个位置,如果硬要擦除的话,也仅仅把蛇擦掉不就行了吗,为什么还要把整个画好的格子跟食物也擦掉呢?你不多此一举,画蛇添足吗!哎,您说的真的没错,但是我这不也是仅仅图个简单吗(但是这个简单真的代价大了点,等运行的时候您就可以看到了,蛇每每前进一步,窗口就抖动一下下,就是这个原因)。擦掉之后需要重绘界面,画食物,画蛇。调用的函数都是一样的,Design(),DrawFood(),DrawSnake() ,不过此时的蛇肯定变了!它已经按照原来的方向向前移动一个格子了。蛇向前移动一个格子,也就是新的节点入队,再将队列的最后一个节点从链表中删掉就可以了。(这里我需要说明下,因为我编程的疏忽,一不小心将蛇头变成蛇尾,蛇尾变成蛇头了,什么意思呢?就是蛇吃食物的那个格子是蛇尾,屁股后面的是蛇头,也就是这里删掉的节点其实是蛇头节点。不过也没什么影响,就是逻辑上有点怪怪的而已,大家迁就点吧。)有关蛇根据原来移动的方向CurrentDirection和所按下的控制键来判断下一步移动的位置,请参考函数NextNode()的代码。那如果考虑蛇吃到食物呢?是不是蛇的长度增加一个格子,并且蛇头(注意:我这里的蛇头就是您逻辑中的蛇尾,理由上面已经讲过了)格子保留下来就可以了。上面的功能如果您实现了,您会发现又有个问题出现了,那就是越界问题。其实在我们最初设计贪吃蛇游戏的时候早就考虑到了,就是一直没把它考虑进去而已。现在来考虑这个问题是再好不过的了。想想NextNode()是计算下一个蛇即将要运动到的节点,肯定得判断下这个节点是不是越界了?是不是碰到蛇它自己了?也很简单,判断越界就是看看按照NextNode()计算出来的下一个格子的坐标是否符合要求就行了(0=x20 & 0=y20),判断是不是碰到蛇,也就是判断这个节点是不是在蛇身上(链表上面)。具体参考函数Hit()。既然这里讲到越界问题,有个与此类似的问题也就出现了。那就是每次随机生成的食物位置,它也是有所限制的。它也不能越界,也不能在蛇的身上,要不然继续生成随机数,具体操作步骤参考函数randomize()。好像问题解决的差不多了吧,不过如果您已经完成了以上的功能,运行程序发现如果你不按键,蛇就不动,那怎么行呢!我们需要每隔一秒无论按不按键蛇头自动向前运动一个格子,那这个怎么实现呢?到MSDN上查查下面两个函数,您可能就瞬间明白该怎么实现这个功能了:SetTimer(),KillTimer(),我们只需要在游戏开始的时候,也就是WM_CREATE中设置一个定时器,开始计时,然后每隔1秒钟(如果您设置的间断时间是1秒钟的话)就会产生WM_TIMER消息,这样只需要在WM_TIMER 消息下编写处理代码就行了,这里的处理代码也是重绘窗口,把蛇新的位置给画出来。至此,这个游戏应该算是完成了。上面只是简单地说说当时我编写该程序时的渐近过程,只是参考而已。这个程序执行起来会有很多的问题。我在编出来之后想使它变的更花哨一点的时候,发现了种种的问题,比方说我在画蛇的时候,每一个蛇节我都用一种随机颜色去画,刚开始的时候运行的好好的,等蛇长度达到一定规模的时候,程序不能正常运行了。有关这些问题,以及前面提到的屏幕抖动的问题,在这里就不再讨论了,小问题而已,相信您可以很好的解决!总之,我觉得贪吃蛇游戏不难,可以作为VC初学者很好的练习素材。希望可以帮助大家提升自己的编程能力,从中炼就自己的编程人生哲学(我是在一本图灵书上看到的,当时感到很震惊!这里套用这句话咯)。 源代码下面是具体的代码,在VC 6.0中就可以运行。只要建个WIN32应用程序就行了。#include #include #include /rand()#include /time() 为了用时间产生随机数种子 srand() #define RowOfFrame 20#define ColumnOfFrame 20#define Width 16#define Height 16bool keydown=false;int randomx;int randomy;struct Node /蛇节int x;int y;Node * next;typedef struct /蛇int length; /蛇长Node *head; /蛇头Node *tail; /蛇尾Snake;enum Directionup=1,down,left,right;Direction CurrentDirection;Snake *greedsnake=new Snake; /贪吃蛇LRESULT CALLBACK WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)/design the window classWNDCLASS wndcls;wndcls.cbClsExtra=0;wndcls.cbWndExtra=0;wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION);wndcls.hInstance=hInstance;wndcls.lpfnWndProc=WinProc;wndcls.lpszClassName=weixin;wndcls.lpszMenuName=NULL;wndcls.style=CS_HREDRAW | CS_VREDRAW;/register the window classRegisterClass(&wndcls);/create the windowHWND hwnd;hwnd=CreateWindow(weixin,贪吃蛇游戏,WS_OVERLAPPEDWINDOW &(WS_MAXIMIZEBOX)&(WS_SIZEBOX),0,0,330,360,NULL,NULL,hInstance,NULL);/show the windowShowWindow(hwnd,SW_SHOWNORMAL);UpdateWindow(hwnd);/the message loopMSG msg;while(GetMessage(&msg,NULL,0,0)TranslateMessage(&msg);DispatchMessage(&msg);return 0;bool Judge(Snake *greedsnake,int randomx,int randomy) /判断随机食物会不会在蛇身上Node *node1=greedsnake-head;int length=greedsnake-length;while(length-)if(node1-x=randomx & node1-y=randomy)return true; /蛇中含有node1节点node1=node1-next;return false; /蛇中没有node1节点void randomize(Snake *greedsnake,int &randomx,int &randomy) /随机产生食物的位置srand(unsigned)time(NULL);randomx=rand()%RowOfFrame;randomy=rand()%ColumnOfFrame;while(Judge(greedsnake,randomx,randomy)randomx=rand()%RowOfFrame; randomy=rand()%ColumnOfFrame;void DrawFood(HDC hdc,int randomx,int randomy) /在蛇吃到之前只能画一次!/COLORREF color;/color=SetDCBrushColor(hdc,RGB(R,G,B);/SetDCBrushColor(hdc,RGB(R,G,B);/ HBRUSH hbrush2=(HBRUSH)GetStockObject(DC_BRUSH);HPEN hpen=CreatePen(PS_SOLID,6,RGB(20,200,200);SelectObject(hdc,hpen);/HBRUSH hbrush2=(HBRUSH)GetStockObject(RGB(80,80,80); /SelectObject(hdc,hbrush2); /SelectObject(hdc,GetStockObject(DC_BRUSH);/SetDCBrushColor(hdc,RGB(R,G,B);Rectangle(hdc,Width*randomx+4,Height*randomy+4,Width*randomx+12,Height*randomy+12);/SelectObject(hdc,WHITE_BRUSH);/界面设计void Design(HDC hdc)HPEN hpen;hpen=CreatePen(PS_DOT,1,RGB(255,0,0);HBRUSH hbrush;hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH);SelectObject(hdc,hpen);SelectObject(hdc,hbrush);int i;for(i=0;i=RowOfFrame;i+)if(MoveToEx(hdc,Width*i,0,NULL) /设置起始点LineTo(hdc,Width*i,Width*RowOfFrame);for(i=0;ix=0;node1-y=0;node1-next=NULL;greedsnake-head=node1;greedsnake-length=1;greedsnake-tail=node1;CurrentDirection=right;/画蛇void DrawSnake(HDC hdc,Snake * greedsnake)int length=greedsnake-length;int x;int y;x=greedsnake-head-x *Width;y=greedsnake-head-y *Height;MoveToEx(hdc,x+8,y+8,NULL);/下面注释的代码是完成画花蛇的功能,但是因为时间的问题会导致程序的运行不正确/给画笔产生随机颜色/*int R,G,B;srand(unsigned)time(NULL);R=rand()%256;G=rand()%256;B=rand()%256;HPEN hpen=CreatePen(PS_SOLID,6,RGB(R,G,B);*/给画笔产生固定的蓝色 HPEN hpen=CreatePen(PS_SOLID,6,RGB(0,0,255); SelectObject(hdc,hpen); if(length=1) LineTo(hdc,x+16,y+8);if(length1)Node *node2=new Node; node2=greedsnake-head;while(-length)/随机产生画笔的颜色 /* R=rand()%256; G=rand()%256; B=rand()%256; hpen=CreatePen(PS_SOLID,6,RGB(R,G,B); SelectObject(hdc,hpen);*/node2=node2-next;int x2;int y2;x2=node2-x*Width+8;y2=node2-y*Height+8;LineTo(hdc,x2,y2);MoveToEx(hdc,x2,y2,NULL);/判断两个节点的坐标是否相等bool Equal(Node *node1,Node *nodetemp)if(node1-x=nodetemp-x & node1-y=nodetemp-y)return true;else return false;/判断是否犯规 nodetemp表示下一个即将入队的节点bool Hit(Snake *greedsnake,Node * nodetemp) /judge if the greed snake hit the wallif(nodetemp-xx=20 |nodetemp-yy=20) return true; /hit the wall/judge if the greed snake hit itselfNode *node1;node1=greedsnake-head;int length=greedsnake-length;while(length-)if(Equal(node1,nodetemp)return true; /hit itselfelsenode1=node1-next;return false;/求蛇下一个运动的地点void NextNode(Snake *greedsnake,Node *node1,char c) /calculate the next pointkeydown=true;if(c=w) /upif(CurrentDirection=down) node1-x=greedsnake-tail-x;node1-y=greedsnake-tail-y+1;elsenode1-x=greedsnake-tail-x;node1-y=greedsnake-tail-y-1;CurrentDirection=up;else if(c=a) /leftif(CurrentDirection=right)node1-x=greedsnake-tail-x+1;node1-y=greedsnake-tail-y;elsenode1-x=greedsnake-tail-x-1;node1-y=greedsnake-tail-y;CurrentDirection=left;else if(c=s) /downif(CurrentDirection=up)node1-x=greedsnake-tail-x;node1-y=greedsnake-tail-y-1; else node1-x=greedsnake-tail-x;node1-y=greedsnake-tail-y+1;CurrentDirection=down;else if(c=d) /rightif(CurrentDirection=left)node1-x=greedsnake-tail-x-1;node1-y=greedsnake-tail-y;elsenode1-x=greedsnake-tail-x+1;node1-y=greedsnake-tail-y;CurrentDirection=right;/将下一个地点加入到蛇身上void Push(Snake *greedsnake,Node *node1)/判断是不是食物if(node1-x!=randomx | node1-y!=randomy) /it is not the location of foodgreedsnake-tail-next=node1; greedsnake-tail=node1; Node *node2=greedsnake-head; greedsnake-head=node2-next; delete node2;elsegreedsnake-tail-next=node1;greedsnake-tail=node1;greedsnake-length+; /吃到食物,蛇的长度要增1 randomize(greedsnake,randomx,randomy);/销毁蛇void Destroy(Snake *greedsnake)Node *node1;node1=greedsnake-head; while(node1-next!=NULL)Node * node2;node2=node1;node1=node1-next;delete node2;greedsnake-length-;LRESULT CALLBACK WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )switch(uMsg)case WM_CHAR:Node * node1;node1=new Node;node1-next=NULL;RECT rect;GetClientRect(hwnd,&rect);HDC hdc;hdc=GetDC(hwnd);HBRUSH hbrush;hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH);SelectObject(hdc,hbrush);switch(wParam) case w: /UP NextNode(greedsnake,node1,w);if(Hit(greedsnake,node1)char sz40;sprintf(sz,The score is %d.nClick OK to exit,greedsnake-length);KillTimer(hwnd,1);MessageBox(hwnd,sz,You Failed,MB_OK);DestroyWindow(hwnd);Push(greedsnake,node1);break;case a: /LEFT NextNode(greedsnake,node1,a);if(Hit(greedsnake,node1)char sz40;sprintf(sz,The score is %d.nClick OK to exit,greedsnake-length);KillTimer(hwnd,1);MessageBox(hwnd,sz,You Failed,MB_OK);DestroyWindow(hwnd);Push(greedsnake,node1);break;case s: /DOWN NextNode(greedsnake,node1,s);if(Hit(greedsnake,node1)char sz40;sprintf(sz,The score is %d.nClick OK to exit,greedsnake-length);KillTimer(hwnd,1);MessageBox(hwnd,sz,You Failed,MB_OK);DestroyWindow(hwnd);Push(greedsnake,node1);break;case d: /RIGHT NextNode(greedsnake,node1,d);if(Hit(greedsnake,node1)char sz40;sprintf(sz,The score is %d.nClick OK to exit,greedsnake-length); KillTimer(hwnd,1);MessageBox(hwnd,sz,You Failed,MB_OK);DestroyWindow(hwnd);Push(greedsnake,node1);break;default: /不是规定的按键,应该将node1节点空间删除掉delete node1;break; Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); /擦除原来的界面/绘制新的界面Design(hdc);DrawSnake(hdc,greedsnake);DrawFood(hdc,randomx,randomy);ReleaseDC(hwnd,hdc); break; case WM_PAINT:PAINTSTRUCT ps;HDC hdc2;hdc2=BeginPaint(hwnd,&ps);/画界面函数Design(hdc2); DrawSnake(hdc2,greedsnake);DrawFood(hdc2,randomx,randomy);EndPaint(hwnd,&ps);break;case WM_CLOSE: KillTimer(hwnd,1); DestroyWindow(hwnd);break;case WM_DESTROY: PostQuitMessage(0);break;case WM_CREATE: /做初始化的一些工作Init(greedsnake);randomize(greedsnake,randomx,randomy);MessageBox(hwnd,上(w) 下(s) 左(a) 右(d),操作说明,0);/TIMER timer;SetTimer(hwnd,1,1000,NULL);break;case WM_TIMER: if(!keydown) Node * node_temp; node_temp=new Node; node_temp-next=NULL; if(CurrentDirection=up) node_temp-x=greedsnake-tail-x; node_temp-y=greedsnake-tail-y-1; if(Hit(greedsnake,node_temp) char sz40; sprintf(sz,The score is %d.nClick OK to exit,greedsnake-length);KillTimer(hwnd,1);M
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025浙江缙云县保安服务有限公司招聘国有企业项目用工10人笔试参考题库附带答案详解
- 2025中国一冶集团建安公司春季校园招聘笔试参考题库附带答案详解
- 危险因素安全培训课件
- 地质灾害滑坡课件
- 地球的内部构造
- 回忆我的母亲课件介绍
- 地球与地球仪课件
- 地板厂安全培训课件
- 危化安全教育培训课件
- 嘉兴消防安全知识培训课件
- 主播岗位职业生涯规划与管理
- 老年综合评估各种表格
- 2025至2030中国牙科手机消耗行业项目调研及市场前景预测评估报告
- NBT 11551-2024 煤矿巷道TBM法施工及验收标准
- 口腔瓷贴面诊疗沟通指南
- 山东安全管理人员大考试题库
- 2025-2030冲牙器行业市场深度调研及发展趋势与投资前景预测研究报告
- 70华诞主题班会课件
- 建筑抗震设计规程(下)DB62T3055-2020
- 商品赠品协议书范本
- 工伤事故赔偿协议书范本
评论
0/150
提交评论