C语言代码链表实现贪吃蛇游戏

本文实例为大家分享了C语言链表实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下

贪吃蛇设计思路:

屏幕坐标:

拓展功能:

1.F1,F2控制加速减速 空格暂停游戏 Esc退出

2.加速每个食物得分更高

先打印出游戏界面,还有初始化蛇,蛇的节点用字符串★表示,游戏背景用■表示,因为这些字符串占两个字节的宽度,所以每次x,y坐标的对应关系是x=y*2。在相应位置打印出蛇,初始化蛇为五个节点

初始化蛇头的移动方向为右,根据按键来确定蛇的移动状态,要是吃到食物,就让食物为蛇头,然后随机生成食物。

重点模块:

蛇移动的实现:

定义一个结构体,里面放节点坐标,和next指针。

蛇每次移动是通过用户按键方向来确定下一个蛇头节点的x,y坐标,新建一个节点赋给下一个坐标,在这个坐标打出蛇的图标,找到尾节点,将尾节点打印成背景图标,再将节点释放,这样蛇就动了一下,以此重复,蛇就可以了动态移动。

食物的实现:

定义一个食物节点,也是一个类似于蛇的结构体指针,通过随机数生成坐标,注意不能在墙上和蛇身上。

用户按键的检测:可以使用wasd的字符来确定方向,但这里我们还需要使用空格,ESC键,上下左右键,所以直接一点,通过GetAsyncKeyState( )函数检测用户输入的按键,需要引用头文件conio.h,_getch()函数用来检测当前是否有按键输入,有的话返回非0的数。

蛇的变速:还是通过GetAsyncKeyState( )函数检测F1,F2,键来确定蛇移动一次Sleep()函数中的毫秒数,这样就实现了蛇的加速减速。而且蛇每移动一次,不必使用system(“cls”)来清屏,通过在循环中snakemove()执行一次,Sleep()函数执行一次,就实现了动态移动。

实现效果:

完整代码:

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> #include<time.h> #include<windows.h> #include<stdlib.h> #include<conio.h> //接收键盘输入输出  #define U 1#define D 2#define L 3 #define R 4  //蛇的状态,U:上 ;D:下;L:左 R:右 /*******定 义 全 局 变 量 *******/typedef struct snake //蛇身的一个节点{ int x; int y; struct snake *next;}snake;int score=0,add=10; //总得分与每次吃食物得分int status,sleeptime=200; //蛇前进状态,每次运行的时间间隔snake *head, *food; //蛇头指针,食物指针snake *q;  //遍历蛇的时候用到的指针int endgamestatus=0; //游戏结束的情况,1:撞到墙;2:咬到自己;3:主动退出游戏。HANDLE hOut; //控制台句柄  /*******函 数 声 明 *******/void gotoxy(int x,int y); //设置光标位置int color(int c);   //更改文字颜色void welcometogame();  //开始界面void createMap();   //绘制地图void scoreandtips(); //游戏界面右侧的得分和小提示void initsnake();   //初始化蛇身,画蛇身void createfood();   //创建并随机出现食物int biteself();    //判断是否咬到了自己void cantcrosswall();  //设置蛇撞墙的情况void speedup(); //加速void speeddown(); //减速void snakemove();   //控制蛇前进方向void keyboardControl();  //控制键盘按键void Lostdraw();   //游戏结束界面void endgame();    //游戏结束void choose(); //游戏失败之后的选择void explation();   //游戏说明 /** * 设置光标位置 */void gotoxy(int x,int y){ COORD c; c.X=x; c.Y=y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);} /** * 文字颜色函数   */int color(int c){ SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);  //更改文字颜色 return 0;}    //开始界面 void welcometogame(){ int n; gotoxy(43,10); color(11); printf("贪 吃 蛇 大 作 战"); color(12); gotoxy(25, 22); printf("1.开始游戏"); gotoxy(45, 22); printf("2.游戏说明"); gotoxy(65, 22); printf("3.退出游戏"); gotoxy(40,27); color(3); printf("请选择 1 2 3:");   color(14); scanf("%d", &n);  //输入选项 switch (n) {  case 1:  system("cls"); createMap();  //创建地图  initsnake();  //初始化蛇身  createfood();  //创建食物  keyboardControl(); //按键控制   break;  case 2:   explation();  //游戏说明函数   break;  case 3:   exit(0);  //退出游戏   break; default:  color(12); gotoxy(40,28); printf("请输入1—3之间的数!"); _getch(); //输入任意键 system("cls"); //清屏 welcometogame(); }}   //创建地图 void createMap(){ int i,j; for(i=0;i<58;i+=2) //打印上下边框 {  gotoxy(i,0); color(5);   printf("□");  gotoxy(i,26);  printf("□"); } for(i=1;i<26;i++) //打印左右边框 {  gotoxy(0,i);  printf("□");        gotoxy(56,i);  printf("□");   } for(i = 2;i<56;i+=2) //打印中间网格 { for(j = 1;j<26;j++) { gotoxy(i,j); color(3); printf("■"); } }}   // 游戏界面右侧的得分和小提示 void scoreandtips(){  gotoxy(64,8); color(14); printf("得分:%d ",score);  gotoxy(64,14); printf("每个食物得分:%d分",add); gotoxy(64,16); printf("不能穿墙,不能咬到自己"); gotoxy(64,18); printf("用↑ ↓ ← →分别控制蛇的移动"); gotoxy(64,20); printf("F1 为加速,F2 为减速"); gotoxy(64,22); printf("space:暂停游戏"); gotoxy(64,24); printf("ESC :退出游戏");}   //初始化蛇身,画蛇身 void initsnake(){ snake *tail; int i; tail=(snake*)malloc(sizeof(snake));//从蛇尾开始,头插法,以x,y设定开始的位置 tail->x=24;   //蛇的初始位置(24,5) tail->y=5; tail->next=NULL; for(i=1;i<=4;i++)  //设置蛇身,长度为5 {  head=(snake*)malloc(sizeof(snake)); //初始化蛇头  head->next=tail;  //蛇头的下一位为蛇尾  head->x=24+2*i;   //设置蛇头位置  head->y=5;  tail=head;    //蛇头变成蛇尾,然后重复循环 } while(tail!=NULL) //从头到尾,输出蛇身 {  gotoxy(tail->x,tail->y); color(14);  printf("★");  //输出蛇身,蛇身使用★组成  tail=tail->next; //蛇头输出完毕,输出蛇头的下一位,一直输出到蛇尾 }}  /** * 随机出现食物 */void createfood(){ snake *food_1; srand((unsigned)time(NULL));   //初始化随机数 food_1=(snake*)malloc(sizeof(snake)); //初始化food_1 while((food_1->x%2)!=0)  //保证其为偶数,使得食物能与蛇头对其,然后食物会出现在网格线上 {  food_1->x=rand()%52+2;    //食物随机出现 } food_1->y=rand()%24+1; q=head; while(q->next==NULL) {  if(q->x==food_1->x && q->y==food_1->y) //判断蛇身是否与食物重合  {   free(food_1);    //如果蛇身和食物重合,那么释放食物指针   createfood();    //重新创建食物  }  q=q->next; } gotoxy(food_1->x,food_1->y); food=food_1; color(12); printf("●");   //输出食物}  /** * 判断是否咬到了自己 */int biteself(){ snake *self;   //定义self为蛇身上的一个节点 self=head->next;  //self是蛇头之外的蛇身上的节点 while(self!=NULL) {  if(self->x==head->x && self->y==head->y) //如果self和蛇身上的节点重合  {   return 1;  //返回1  }  self=self->next; } return 0;}  /** * 设置蛇撞墙的情况 */void cantcrosswall(){  if(head->x==0 || head->x==56 ||head->y==0 || head->y==26) //如果蛇头碰到了墙壁 {  endgamestatus=1;  //返回第一种情况  endgame();    //出现游戏结束界面 }}   /** * 加速,蛇吃到食物会自动提速,并且按F1会加速 */void speedup(){ if(sleeptime>=50) { sleeptime=sleeptime-10; add=add+2;  }} /** * 加速,按F2会减速 */void speeddown(){ if(sleeptime<350)    //如果时间间隔小于350 {  sleeptime=sleeptime+30;  //时间间隔加上30  add=add-2;     //每吃一次食物的得分减2  }} /** * 控制方向 问题:为什么要设置status,而不使用前两章中接收键盘按键的方法 */void snakemove() //蛇前进,上U,下D,左L,右R{ snake * nexthead; cantcrosswall(); nexthead=(snake*)malloc(sizeof(snake)); //为下一步开辟空间 if(status==U) {  nexthead->x=head->x;  //向上前进时,x坐标不动,y坐标-1  nexthead->y=head->y-1;  nexthead->next=head;  head=nexthead;  q=head;     //指针q指向蛇头  if(nexthead->x==food->x && nexthead->y==food->y) //如果下一个有食物 下一个位置的坐标和食物的坐标相同  {      while(q!=NULL)   {    gotoxy(q->x,q->y); color(14);    printf("★");  //原来食物的位置,从●换成★    q=q->next;   //指针q指向的蛇身的下一位也执行循环里的操作    }   score=score+add;  //吃了一个食物,在总分上加上食物的分 speedup();   createfood();   //创建食物  }  else        {   while(q->next->next!=NULL) //如果没遇到食物   {    gotoxy(q->x,q->y);    color(14);    printf("★");   //蛇正常往前走,输出当前位置的蛇身    q=q->next;    //继续输出整个蛇身   }   gotoxy(q->next->x,q->next->y); //经过上面的循环,q指向蛇尾,蛇尾的下一位,就是蛇走过去的位置 color(3);   printf("■");   free(q->next);  //进行输出■之后,释放指向下一位的指针   q->next=NULL;  //指针下一位指向空  } } if(status==D) {  nexthead->x=head->x;  //向下前进时,x坐标不动,y坐标+1  nexthead->y=head->y+1;  nexthead->next=head;  head=nexthead;  q=head;  if(nexthead->x==food->x && nexthead->y==food->y) //有食物  {      while(q!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;   }   score=score+add; speedup();   createfood();  }  else        //没有食物  {   while(q->next->next!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;   }   gotoxy(q->next->x,q->next->y); color(3);   printf("■");   free(q->next);   q->next=NULL;  } } if(status==L) {  nexthead->x=head->x-2;  //向左前进时,x坐标向左移动-2,y坐标不动  nexthead->y=head->y;  nexthead->next=head;  head=nexthead;  q=head;  if(nexthead->x==food->x && nexthead->y==food->y)//有食物  {   while(q!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;   }   score=score+add; speedup();   createfood();  }  else        //没有食物  {   while(q->next->next!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;     }   gotoxy(q->next->x,q->next->y); color(3);   printf("■");   free(q->next);   q->next=NULL;  } } if(status==R) {  nexthead->x=head->x+2;  //向右前进时,x坐标向右移动+2,y坐标不动  nexthead->y=head->y;  nexthead->next=head;  head=nexthead;  q=head;  if(nexthead->x==food->x && nexthead->y==food->y)//有食物  {   while(q!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;   }   score=score+add; speedup();   createfood();  }  else           //没有食物  {   while(q->next->next!=NULL)   {    gotoxy(q->x,q->y);    color(14);    printf("★");    q=q->next;     }   gotoxy(q->next->x,q->next->y); color(3);   printf("■");   free(q->next);   q->next=NULL;  } } if(biteself()==1)  //判断是否会咬到自己 {  endgamestatus=2;  endgame(); }}  /** * 控制键盘按键 */void keyboardControl(){ status=R;  //初始蛇向右移动 while(1) { scoreandtips();  if(GetAsyncKeyState(VK_UP) && status!=D)   //GetAsyncKeyState函数用来判断函数调用时指定虚拟键的状态  {   status=U;   //如果蛇不是向下前进的时候,按上键,执行向上前进操作  }  else if(GetAsyncKeyState(VK_DOWN) && status!=U)  //如果蛇不是向上前进的时候,按下键,执行向下前进操作  {   status=D;  }  else if(GetAsyncKeyState(VK_LEFT)&& status!=R)  //如果蛇不是向右前进的时候,按左键,执行向左前进  {   status=L;  }  else if(GetAsyncKeyState(VK_RIGHT)&& status!=L)  //如果蛇不是向左前进的时候,按右键,执行向右前进  {   status=R;  }  if(GetAsyncKeyState(VK_SPACE)) //按暂停键,执行pause暂停函数  {   while(1) { Sleep(300); //sleep()函数,头文件#include <unistd.h> 另进程暂停,知道达到里面设定的参数的时间。 if(GetAsyncKeyState(VK_SPACE))  //按空格键暂停 {  break; }  }    }  else if(GetAsyncKeyState(VK_ESCAPE))  {   endgamestatus=3; //按esc键,直接到结束界面   break;  }  else if(GetAsyncKeyState(VK_F1)) //按F1键,加速  {   speedup();  }  else if(GetAsyncKeyState(VK_F2)) //按F2键,减速  {   speeddown();     }  Sleep(sleeptime);  snakemove(); }}  /** 游戏说明*/void explation(){ //int i,j = 1; system("cls"); // color(13); // gotoxy(44,3); // printf("游戏说明"); // color(2); // for (i = 6; i <= 22; i++) //输出上下边框=== //{ // for (j = 20; j <= 75; j++) //输出左右边框|| // { // gotoxy(j, i); // if (i == 6 || i == 22) printf("="); // else if (j == 20 || j == 75) printf("||"); // } //} color(3); gotoxy(30,8); printf("1. 不能穿墙,不能咬到自己"); color(10); gotoxy(30,11); printf("2. 用↑.↓.←.→分别控制蛇的移动"); color(14); gotoxy(30,14); printf("3. F1 为加速,F2 为减速"); color(11); gotoxy(30,17); printf("4. 按空格键暂停游戏,再按空格键继续"); color(4); gotoxy(30,20); printf("5. ESC :退出游戏.space:暂停游戏"); _getch();    //按任意键返回主界面 system("cls"); welcometogame();}   /** * 结束游戏 */void endgame(){ system("cls"); if(endgamestatus==1) {   //Lostdraw(); gotoxy(43,9);  color(12); printf("GAME OVER !"); } else if(endgamestatus==2) {    //Lostdraw();  gotoxy(43,9);  color(12);  printf("GAME OVER !"); } else if(endgamestatus==3) { //Lostdraw(); gotoxy(40,9);  color(12);  printf("已结束游戏。"); } gotoxy(43,12); color(13); printf("你的得分是 %d",score); choose();} /** * 边框下面的分支选项 */void choose(){ int n; gotoxy(25,23); color(12); printf("Continue ------ 1"); gotoxy(52,23); printf("Exit ------ 2"); gotoxy(45,25); color(11); printf("选择: "); scanf("%d", &n); switch (n) { case 1: system("cls");   //清屏 score=0;    //分数归零 sleeptime=200; //设定初始速度 add = 10; //使add设定为初值,吃一个食物得分10,然后累加 welcometogame(); break; case 2: exit(0);    //退出游戏 break; default: gotoxy(35,27); color(12); printf(" 输入有误 重新输入 !"); system("pause >nul"); endgame(); choose(); break; } }/** * 失败界面 */void Lostdraw(){ system("cls"); int i; gotoxy(45,2); color(6); printf("\\\\\\|///"); gotoxy(43,3); printf("\\\\"); gotoxy(47,3); color(15); printf(".-.-"); gotoxy(54,3); color(6); printf("//");  gotoxy(44,4); color(14); printf("(");  gotoxy(47,4); color(15); printf(".@.@");  gotoxy(54,4); color(14); printf(")");  gotoxy(17,5); color(11); printf("+------------------------");  gotoxy(35,5); color(14); printf("oOOo");  gotoxy(39,5); color(11); printf("----------");  gotoxy(48,5); color(14); printf("(_)");  gotoxy(51,5); color(11); printf("----------");  gotoxy(61,5); color(14); printf("oOOo");  gotoxy(65,5); color(11); printf("-----------------+");  for(i = 6;i<=19;i++)  //竖边框 { gotoxy(17,i); printf("|"); gotoxy(82,i); printf("|"); }  gotoxy(17,20); printf("+---------------------------------");  gotoxy(52,20); color(14); printf("☆☆☆〃");  gotoxy(60,20); color(11); printf("----------------------+"); } /*** 主函数*/int main(){  system("mode con cols=100 lines=30"); //设置控制台的宽高 //printsnake(); welcometogame();  keyboardControl(); endgame(); return 0;}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

青春一经典当即永不再赎

C语言代码链表实现贪吃蛇游戏

相关文章:

你感兴趣的文章:

标签云: