收藏 分享(赏)

贪吃蛇设计思路.docx

上传人:weiwoduzun 文档编号:5620683 上传时间:2019-03-10 格式:DOCX 页数:17 大小:66.93KB
下载 相关 举报
贪吃蛇设计思路.docx_第1页
第1页 / 共17页
贪吃蛇设计思路.docx_第2页
第2页 / 共17页
贪吃蛇设计思路.docx_第3页
第3页 / 共17页
贪吃蛇设计思路.docx_第4页
第4页 / 共17页
贪吃蛇设计思路.docx_第5页
第5页 / 共17页
点击查看更多>>
资源描述

1、贪吃蛇游戏设计思路我前一段时间写了个贪吃蛇,有位吧友求思路,而网上也没有类似的教程帖子(至少我当初没找到(-_-),我只找到了现成的代码) ,于是乎,我就整理了一下自己的设计思路,写下了这篇东西,如果你是老鸟,有什么说错的地方还希望您具体指出来,毕竟我的功力还不深。 。 。 。 。 。 。如果你是新手,大家一起交流探讨吧,我也算是刚入门的新手。在本帖最后,我会附上自己写的完整的程序代码,里面也有一些注释,以供大家参考。首先,看看我的贪吃蛇的程序框图。从图中可以看出,整个游戏就是一个大的循环,当判断蛇的生命值为 0 时就跳出循环游戏结束,否则继续游戏。常用的结构是:While (1)/游戏内容I

2、f ()break;/满足游戏结束的条件时跳出循环结束游戏解决了游戏的主体结构,接下来就是游戏的具体内容了。先来看看我们需要哪些变量;蛇的身体(链表,包含了蛇每一节的坐标,和生命值) ;食物(数组,两个元素,包含了食物的坐标) ;蛇的运动方向(整型,共四个值) ;首先,蛇的身体应该选用什么数据类型来存储呢?数组组是肯定不行的,因为数组的大小是固定的,你不知道你的蛇最终能达到多长(或许有高手能让蛇长到占满屏幕?) ,而且在数组的头部插入数据是很麻烦的一件事,你必须把所有的数据都往后移动一个元素才行。因此,此处我选用了链表来储存蛇的身体信息, (有的小伙伴要问了:什么是链表啊?这个请自行百度,我的

3、个人看法是,链表就是对结构体的一种应用。话说我们学了一学期的 C 语言,老师也没讲链表之类的东西,不知道很正常,它应该属于数据结构这一门学科的内容吧。如果你不懂链表也没关系,数组完全可以代替它,只是在资源的利用上要浪费一点,在数据的插入与删除上要麻烦一点而已) 。链表的一个节点应该包含哪些内容呢?首先是蛇的坐标 x 和 y,然后是生命值(其实只有第一个节点能用上它,你也可以去掉它,然后另外单独定义一个全局变量如 life 来判断蛇的生死) ,最后是指向下一个节点的结构体指针。定义如下:struct snk/蛇身体 int x;int y;int life;struct snk *link;然后

4、是食物:int food2;/食物,用 food0表示 x 坐标,用 food1表示 y 坐标当然,食物必须定义为全局的。当然如果你有需要,还可以定义一个全局整型变量来保存积分:int fen=0;/积分需要的主要数据已经定义好,接下来是初始化。那么,就先来初始化蛇的身体,创建一个链表;struct snk *snake;/指向蛇链表头(第一个节点)的结构体指针 /声明两个个链表节点,初始化最开始的几节蛇身体snake=(struct snk *)malloc(sizeof(struct snk);snake-x=10;snake-y=10;snake-life=1;snake-link=(s

5、truct snk *)malloc(sizeof(struct snk);snake-link-x=10;snake-link-y=9;snake-link-x=10;snake-link-link=NULL;这里我只初始化了两节,你也可以多加几节,但是,最后别忘了把最后一个节点的 link 指针设为空,它标志着蛇的结尾,至于 life,只需把第一个节点初始化为非零值即可。接下来是初始化食物,为了能够随机生成食物,我们需要用到 time.h 为我们提供的随机函数,rand()和 srand();为了方便后面的食物生成,我们把食物生成单独做成一个函数 mkfood() ,想一想,它需要哪些参数

6、,它的返回值是什么?为了防止生成的食物的坐标与蛇的身体重合,所以 mkfood 函数需要知道蛇的状态,食物是全局变量,因此函数不需要返回值,因此 mkfood 函数的函数首部应该是void mkfood(struct snk *p);/产生食物每次调用它都需要用 srand 函数重设随机数种子,然后用 rand 函数产生随机数,分别赋值给 food0和 food1作为食物的 x 坐标和 y 坐标。在这之后,需要遍历一次蛇的每一个节点,并把它们与食物的坐标比较,如有相同的,既产生的食物和蛇的身体重复了,就必须重新设定食物的坐标,这里我用的是递归调用 mkfood 函数来重新设定食物坐标。如果你用

7、递归方法来重设食物坐标,不得不提的是当你在设定随机数种子时不要使用 time()函数,因为 time 函数只能精确到秒,一旦食物与蛇身体重复,就会递归调用 mkfood 函数,此时时间还远远不足一秒,所以导致随机数种子还是和原来的一样,产生的随机数也和原来一样,还是和蛇身体重复,如此循环往复的递归调用,以现在的 CPU 运算能力,一秒钟之内可以进行的运算次数是相当惊人的,最终导致栈的溢出,程序崩溃。 。 。 。所以应该选用更加精确的函数,比如 clock()它返回从程序启动,到调用它时经过的时间,单位是毫秒,或者干脆手动设定一个变量来做种子,每次调用之前更新这个变量。接下来就是制作一个函数,能

8、够按照蛇身体和食物的信息,把蛇的身体和食物打印(绘制)到屏幕的相应位置。这个函数需要知道蛇和食物的坐标,食物是全局变量可以直接获取坐标,因此它接受一个结构体指针类型的参数,就是蛇身体的第一个节点,而它不需要返回值。所以他的函数首部应该是:void drawmap(struct snk *p,int *fd);/画出食物和蛇至于函数内部,我们可以通过 p-x 或者 p-y 来访问蛇的头部的坐标,然后令 p=p-link;来继续访问接下来一节蛇的坐标,直到 p-link=NULL,这说明蛇到了结尾了。食物是全局变量可以直接获取坐标。获得坐标之后,你可以调用图形库来绘制,也可以在字符界面打印。总之就

9、是遍历一次蛇的身体,根据每一个节点的坐标,分别把它们和食物一起打印在屏幕上就是了。接下来是蛇的移动问题,怎样让蛇自动的移动呢?这个只需要主循环 while(1)每循环一次就改变一次蛇的位置即可,那么如何改变呢?这就体现出我们为什么要用链表来储存蛇的坐标了。我们并不需要改变蛇每一节的坐标,只需要“添头去尾”即可移动蛇,我们只需要在蛇的头部,根据蛇的运动方向添加一个节点,把它设为蛇头,判断此节点的坐标是否超出地图范围,如果超出这修改生命值为死亡,如果没有超出,则继续把它与食物的坐标进行比较,如果不同,则删除蛇的最后一个节点,蛇就向前移动一格了,如果相同,则蛇吃到了食物,此时不删除最后一节蛇的身体,

10、蛇就增加了一节,然后再调用 mkfood 函数重新生成食物覆盖掉原来食物的坐标。此处最主要的就是链表的添头去尾操作,添头其实就是新分配一块内存,把它的 link 指针指向原来的第一个节点,再把现在的第一个节点的地址返回给代表蛇头的结构体指针变量(把新添加的节点设为蛇头) ,去尾就是把最后一个节点用 free()释放掉,把倒数第二个节点的 link 设为 NULL 即可。还有就是如何确定添加的头的坐标的问题,你需要根据之前的头的坐标和代表方向的变量的值来做,比如用 1234 分别代表上下左右方向,当方向为 1 时,蛇向上运动,那么在原来的蛇头的基础上把 x 减 1,y 不变来作为新头的坐标。其他

11、方向同理。然后是蛇的控制问题,我们,可以用一个函数来获取输入,改变蛇的前进方向;它需要接收当前的运动方向(整型值) ,用来判断用户按下的方向是否与其相反(蛇不能向与当前方向相反的方向前进),然后返回一个运动方向,所以他的函数首部应该是:int keydown(int z)/获取输入这个函数里,我们可以使用 conio.h 里的 getch 来获取键盘输入,为什么不用 getchar 或者 scanf 呢?因为 getch 与 getchar()虽然基本功能差不多,差别是 getch()直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch 就立刻返回,而 getchar 则是从输入

12、缓冲区获取键值, getch 返回值是用户输入的 ASCII 码,出错返回-1.输入的字符不会回显在屏幕上。但是还有一个问题,那就是当程序执行到 getch 时会暂停,等待用户输入。这样如果我们不按键盘,游戏就无法继续。这个可以用 conio.h 里提供的kbhit()函数来检测是否有键盘被按下,函数名:kbhit()(VC+6.0 下为_kbhit())功 能及返回值: 检查当前是否有键盘输入,若有则返回一个非 0 值,否则返回 0用 法:int kbhit(void);包含头文件: include 于是我们可以这样写:char ch;if(kbhit()ch=getch();switch(

13、ch)case a:。 。 。 。 。 。;break;case d:。 。 。 。 。 。;break;case w:。 。 。 。 。 。;break;case s:。 。 。 。 。 。;break;default :break;根据按的键的不同来修改蛇的运动方向。注意哦!在改变运动方向时不要忘记判断方向是否与当前的方向冲突!我们还可以用它来判断按下的是否是 Esc 键,如果是,则结束游戏。至此,我们已经完成了贪吃蛇的最主要两个数据:Food2和 snakeInt x;Int y;Int life ;Struct snake *link ;几个主要的功能函数,void drawmap(s

14、truct snk *p,struct food *fd);/画地图食物和蛇 int keydown(int z);/获取输入 struct snk * mvsnk(struct snk *p,int z,struct food *fd);/移动并更新蛇的坐标 struct food * mkfood(struct snk *p);/产生食物接下来就是将它们按照开始的程序框图组合起来,一条新鲜的贪吃蛇就出炉了!当然,你还可以在最外面再套一个大循环以实现多次游戏。如果你没有 ege 图形库,只需要稍微更改几个绘制图形的函数,就可以在控制台的字符界面实现了。你也可以下载这里的编译完成的 exe,和

15、我修改的字符界面版:Exe 文件:http:/ 图形库版:http:/ exe 的源代码)以下是完整代码,其中使用了 ege 图形库,除了文中提到的,我还增加了保存最高纪录的功能。/|-|#include #include #include #include void msgbox(int x,int y,int l,int h,char *c,char *c2,char *c3);void drd(int x,int y);/画点 void drl(int x1,int y1,int x2,int y2);/画线 void drawmap(struct snk *p);/里用上面两个函数画地

16、图食物和蛇 int keydown(int z);/获取输入 struct snk * mvsnk(struct snk *p,int z);/更新蛇的坐标 void mkfood(struct snk *p);/产生食物 int food2=20,15;struct snk/蛇身体 int x;int y;int life;struct snk *link;int speed=100; int fen=0;/积分 int jilu;/最高分记录 char jiluzhe20;int main()/初始化,FILE *fp;/从文件载入最高记录 if(fp=fopen(“jiulu.txt“,

17、“r“)=NULL)jilu=0;else fgets(jiluzhe,20,fp);fscanf(fp,“%d“,fclose (fp);initgraph(600,600);/定义屏幕为600*600像素setcaption(“贪吃蛇“); setcolor(WHITE);setfont(20,0,“宋体“);int z=4;struct snk *snake;/指向蛇链表头的结构体指针 struct snk *snakelink;/用于游戏结束后释放内存时的临时存储 struct food *fd;/指向食物的结构体指针 /声明四个链表节点为初始的四节蛇身体snake=(struct s

18、nk *)malloc(sizeof(struct snk);snake-x=10;snake-y=10;snake-life=1;snake-link=(struct snk *)malloc(sizeof(struct snk);snake-link-x=10;snake-link-y=9;snake-link-link=(struct snk *)malloc(sizeof(struct snk);snake-link-link-x=10;snake-link-link-y=8;snake-link-link-link=(struct snk *)malloc(sizeof(struct

19、 snk);snake-link-link-link-x=10;snake-link-link-link-y=7;snake-link-link-link-link=NULL;setfontbkcolor(BLUE);setfont(30,0,“宋体“);xyprintf(0,300,“W:上 S:下 A:左 D:右 Esc:结束游戏退出“);setfont(20,0,“宋体“);Sleep(2300);/游戏主循环 -|while(1)int temp_z;temp_z=z; z=keydown(z);if(z=27)break;if(z=5)outtextxy(300,300,“暂停“);

20、getch();z=temp_z;/*|*/snake=mvsnk(snake,z);if (snake-life=0)break;drawmap(snake);Sleep(300-speed);setfont(50,0,“宋体“);setcolor(YELLOW);setfontbkcolor(BLUE);outtextxy(175,250,“GAME OVER!“);setcolor(WHITE);Sleep(1500);if (fenjilu)inputbox_getline(“恭喜!打破纪录了!“,“您打破了最高记录!n留下您的大名吧!n按回车确认输入“,jiluzhe,20);fp=

21、fopen(“jiulu.txt“,“w“);fprintf(fp,“%sn%d“,jiluzhe,fen);fclose (fp);Sleep(1500);while(snake!=NULL)snakelink=snake-link;free(snake);snake=snakelink; fen=0;speed=100;closegraph();return 0;/-|int keydown(int z)/获取输入 char ch;if(kbhit()ch=getch();switch(ch)case A:case a:if(z!=2)z=1;break;case D:case d:if(

22、z!=1)z=2;break;case W:case w:if(z!=4)z=3;break;case S:case s:if(z!=3)z=4;break;case E:case e:z=5;break;default :break;if(ch=27)z=27;return z;void msgbox(int x,int y,int l,int h,char *c,char *c2,char *c3)setfillcolor(LIGHTGRAY);bar(x,y,x+l,y+h);setfillcolor(WHITE);bar(x+3,y+3,x+l-3,y+h-3);setfillcolo

23、r(BLUE);bar(x+3,y+3,x+l-3,y+30);setfontbkcolor(WHITE);setcolor(BLACK);rectprintf(x+5,y+3,l-5,h-3,“%s%s%s“,c,c2,c3);setfontbkcolor(BLUE);setcolor(WHITE);struct snk * mvsnk(struct snk *p,int z)/更新蛇的坐标 struct snk *p2;struct snk *p3;int x,y;x=p-x;y=p-y;switch(z)case 1:x-;break;case 2:x+;break;case 3:y-;

24、break;case 4:y+;break;/在蛇的头部添加一个节点 p2=(struct snk *)malloc(sizeof(struct snk);p2-x=x;p2-y=y;p2-link=p;p2-life=1;/判断蛇头是否碰到身体 p3=p;while(p3!=NULL)if (p2-x=p3-xp3=p3-link; /判断蛇头是否碰到墙壁 if (p2-x28|p2-y28|p2-xylife=0;if (p2-x=food0fen+;speedlink-link!=NULL)p=p-link;p3=p-link;p-link=NULL;free(p3);/如果没有吃到食物

25、则删除最后一个节点return p2;void mkfood(struct snk *p)struct snk *p2;p2=p;srand(unsigned)clock();/设定随机数种子 food1=rand()%26+3;/随机产生食物坐标 food0=rand()%27+1;/检测食物的坐标是否与蛇身体重复,如果是,则重新生成食物 doif (food0=p-x p=p-link; while(p!=NULL);void drd(int x,int y)/画点 setfillcolor(GREEN);x=x*20;y=y*20;bar(x+1,y+1,x+19,y+19);void drl(int x1,int y1,int x2,int y2)/画线 int x,y;setfillcolor(GREEN);dox=x1*20;y=y1*20;bar(x+1,y+1,x+19,y+19);x1x,p-y);drd(food0,food1);p=p-link;while(p!=NULL)drd(p-x,p-y);p=p-link;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报