C语言单链表贪吃蛇小游戏
C语言实现单链表控制台贪吃蛇小游戏,供大家参考。
编译环境:vs2019
需求:
统计游戏开始后的时间,控制贪吃蛇;吃到食物蛇身加长,得分加一;碰墙或蛇头碰到身体减一条生命;生命消耗完则结束游戏。
思路:
使用wasd键控制蛇的移动方向,蛇头碰到食物得分加一,并在地图上随机产生一个食物,累加得分,碰墙或碰自己减一条生命,并初始化整条蛇,生命值为0时结束游戏。
做法:
使用单链表控制贪吃蛇移动的核心思想就是:链表存储贪吃蛇所有坐标,每次循环贪吃蛇不断向一个方向插入一个新的结点作为新的蛇头,按下按键控制新蛇头产生的位置,然后从新蛇头处遍历链表输出蛇身到上一个蛇尾,清除上一个蛇尾的痕迹,并释放相关结点。
每次向链表插入新节点后,判断新节点的坐标是否和食物的坐标重合,如果重合本轮循环不释放清除蛇尾结点,反之释放清除上一个蛇尾的结点。
另外,在写蛇生命相关代码的时候,还需要注意一下哪些值应该初始化,哪些值不应该初始化。
只要明白了贪吃蛇运动的核心思想,整个程序其实就不难写出来。
难点:
wsad控制贪吃蛇上下左右移动,并清除蛇尾。
说明:
使用单链表实现贪吃蛇的核心思想是我一开始没有想到的,部分相关代码我学习并借鉴了一些网络上搜索到的代码,如果有违反了相关版权协议,请告知我修改相关代码。
注意:
由于编译器原因程序中_kbhit()和_getch()函数可能在其他编译器上编译会出现错误,解决办法是去掉函数前面的“_”。
运行效果:
代码实现:
#include#include #include #include #include voidHideCursor();//光标隐藏 voidgotoxy(intx,inty);//光标定位 typedefstructsnake { intx; inty; structsnake*next; }snake; #defineWIDTH100//控制台窗口宽度 #defineHEIGHT30//控制台窗口高度 #defineSNAKEN4//贪吃蛇初始长度 #defineLIFE3//初始生命次数 #defineSPEED200//游戏速度、循环休眠时间 #defineU1//使用宏代替需要数字代替的蛇的行动方向 #defineD2//宏名含义是各方向英文单词首字母 #defineL3//蛇的状态,U:上;D:下;L:左R:右 #defineR4 voiddtxxcsh()//输出地图 { for(inti=1;i next=NULL; tail->x=HEIGHT-6; tail->y=8; //贪吃蛇初始长度5SNAKEN for(i=1;i<=SNAKEN;i++)//在蛇尾处创建链表 { head=(snake*)malloc(sizeof(snake)); head->next=tail; head->x=24+i*2;//head->x这个数必须为偶数,和食物坐标偶数对应 head->y=8; tail=head;//此时蛇尾指针指向蛇头 } while(tail) { gotoxy(tail->x,tail->y); printf("■"); tail=tail->next; } } intstatus=R;//蛇前进状态 snake*p=NULL;//工作指针 snake*nexthead;//下一个蛇头 intscore=0;//得分 voidsnakemove()//蛇前进,上U,下D,左L,右R { nexthead=(snake*)malloc(sizeof(snake)); if(status==U) { nexthead->y=head->y-1;//确定新蛇头的下一个坐标x,y nexthead->x=head->x; } if(status==D)//下 { nexthead->y=head->y+1; nexthead->x=head->x; } if(status==L)//左 { nexthead->x=head->x-2; nexthead->y=head->y; } if(status==R)//右 { nexthead->x=head->x+2; nexthead->y=head->y; } nexthead->next=head; head=nexthead; p=head; if(p->x==foodx&&p->y==foody)//判断蛇头的位置是否和食物的位置重合 { while(p)//输出尾结点 { gotoxy(p->x,p->y); if(p==head) printf("●"); else printf("■"); p=p->next;//因为每次运动都是新创建一个头结点再删除一个尾结点, }//所以要增加一节身体,只需要这次循环不释放尾结点,并输出一次尾结点就好了 //sjcsswhs();//碰到食物则再产生一个食物 score++; gotoxy(32,28); printf("%d",score); } else { while(p->next->next)//不输出尾结点 { gotoxy(p->x,p->y); if(p==head) printf("●"); else printf("■"); p=p->next; } gotoxy(p->next->x,p->next->y); printf(""); free(p->next); p->next=NULL; } p=head; while(p)//如果食物的坐标刷新到了蛇身上则再产生一个食物* { if(p->x==foodx&&p->y==foody) sjcsswhs(); p=p->next; } } voidczfxhs()//操作方向函数,接收从键盘输入的按键,控制贪吃蛇行进方向 { charch=_getch(); switch(ch) { case'w': if(status!=D) status=U;break; case's': if(status!=U) status=D;break; case'a': if(status!=R) status=L;break; case'd': if(status!=L) status=R;break; case'': _getch();break;//空格暂停 } } intyxjstjjsmz_1()//生命掉落条件1咬自己 { snake*self=head->next;//self为蛇身上的一个结点 while(self) { if(self->x==head->x&&self->y==head->y)//head和self的成员作比较,蛇头一直存在,这里遍历的是蛇身 { return1; } self=self->next; } return0; } intyxjstjjsmz_2()//生命掉落条件2碰墙 { if(head->x<=1||head->x>=98||head->y<=0||head->y>=26) return1; return0; } inti=LIFE-1;//变量存储生命次数 voidqcsytmslbhs()//清除并释放上一条蛇留下来的痕迹,更新生命信息 { p=head; int_x_=p->x;//用于保存死掉的蛇的蛇头处的位置,用于输出被蛇头顶掉的墙壁 int_y_=p->y; while(head) { gotoxy(head->x,head->y); printf(""); head=head->next; free(p); p=head; } gotoxy(52,28);//更新生命信息 printf("%d",i); if(_y_==0||_y_==HEIGHT-4)//用于在蛇死掉后,蛇头的位置输出被清除蛇头顶替掉的墙壁 { gotoxy(_x_,_y_); printf("--"); } elseif(_x_==WIDTH-2) { gotoxy(_x_+1,_y_); printf("|"); } elseif(_x_==0) { gotoxy(_x_,_y_); printf("|"); } } voidsbjsjmhs()//失败结束界面 { p=head;//释放内存 while(head) { head=head->next; free(p); p=head; } system("cls"); gotoxy(45,12); printf("游戏结束!"); gotoxy(44,14); printf("最终得分:%d",score); gotoxy(0,28); } intupdatetime()//获取一次电脑现在的时间 { intnow; SYSTEMTIMEsystem_time; GetLocalTime(&system_time); now=system_time.wMinute*60+system_time.wSecond; returnnow; } inttime_1=updatetime();//保存游戏刚开始的时间 voidgametime()//写在每次循环之内 { inttime_2=updatetime()-time_1;//更新游戏开始后时间,用现在的时间减去刚开始的时间 gotoxy(72,28); printf("%ds",time_2); } intmain()//主函数 { system("modeconcols=100lines=30");//设置控制台大小 system("title贪吃蛇游戏");//设置标题 HideCursor();//隐藏光标 sjcsswhs();//初始化随机产生一个食物 dtxxcsh();//初始化地图、信息 for(;i>=0;i--)//生命 { cshs();//初始化蛇的位置 status=R;//初始化运动方向 while(1) { snakemove();//蛇行动动画,方向被控制变量控制 if(_kbhit()) { czfxhs();//接收键盘按键,控制控制变量 } if(yxjstjjsmz_1()||yxjstjjsmz_2())//两个掉落生命的条件 break; gametime();//更新游戏时间 Sleep(SPEED); } qcsytmslbhs();//清除上一条蛇留下来的痕迹,更新生命信息 } sbjsjmhs();//失败结束界面 return0; } voidHideCursor() { CONSOLE_CURSOR_INFOcursor_info={1,0}; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info); } voidgotoxy(intx,inty) { COORDpos={x,y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos); }
不足之处:
因为这是我第一次使用链表做一个完整的小程序,所以对链表的运用还很稚嫩,在代码规范和严谨性上面还有很多问题。
另外关于“食物如果刷新到蛇身上则再随机产生一个食物”(172行)相关代码,我不是很确定到底完不完善。
作为一名c语言新手,我对未知的知识始终抱有学习和谦卑的态度,如有贵人能够对我的程序提出建议,我将不胜感激。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。