C语言单链表贪吃蛇小游戏分享!

C语言实现单链表控制台贪吃蛇小游戏,供大家参考。

编译环境:vs2019

需求:

统计游戏开始后的时间,控制贪吃蛇;吃到食物蛇身加长,得分加一;碰墙或蛇头碰到身体减一条生命;生命消耗完则结束游戏。

思路:

使用wasd键控制蛇的移动方向,蛇头碰到食物得分加一,并在地图上随机产生一个食物,累加得分,碰墙或碰自己减一条生命,并初始化整条蛇,生命值为0时结束游戏。

做法:

使用单链表控制贪吃蛇移动的核心思想就是:链表存储贪吃蛇所有坐标,每次循环贪吃蛇不断向一个方向插入一个新的结点作为新的蛇头,按下按键控制新蛇头产生的位置,然后从新蛇头处遍历链表输出蛇身到上一个蛇尾,清除上一个蛇尾的痕迹,并释放相关结点。

每次向链表插入新节点后,判断新节点的坐标是否和食物的坐标重合,如果重合本轮循环不释放清除蛇尾结点,反之释放清除上一个蛇尾的结点。

另外,在写蛇生命相关代码的时候,还需要注意一下哪些值应该初始化,哪些值不应该初始化。
只要明白了贪吃蛇运动的核心思想,整个程序其实就不难写出来。

难点:

wsad控制贪吃蛇上下左右移动,并清除蛇尾。

说明:

使用单链表实现贪吃蛇的核心思想是我一开始没有想到的,部分相关代码我学习并借鉴了一些网络上搜索到的代码,如果有违反了相关版权协议,请告知我修改相关代码。

注意:

由于编译器原因程序中_kbhit()和_getch()函数可能在其他编译器上编译会出现错误,解决办法是去掉函数前面的“_”。

运行效果:

C语言单链表贪吃蛇小游戏

代码实现:

  #include <stdio.h>  #include <stdlib.h>  #include <conio.h>  #include <time.h>  #include <windows.h>    void HideCursor();  //光标隐藏  void gotoxy(int x, int y); //光标定位    typedef struct snake  {   int x;   int y;   struct snake* next;  }snake;    #define WIDTH 100  //控制台窗口宽度  #define HEIGHT 30  //控制台窗口高度  #define SNAKEN 4  //贪吃蛇初始长度  #define LIFE 3  //初始生命次数  #define SPEED 200  //游戏速度、循环休眠时间  #define U 1   //使用宏代替需要数字代替的蛇的行动方向  #define D 2   //宏名含义是各方向英文单词首字母  #define L 3   //蛇的状态,U:上 ;D:下;L:左 R:右  #define R 4         void dtxxcsh()  //输出地图  {     for (int i = 1; i < WIDTH-1; i++) //输出上下面墙   {   gotoxy(i, 26);   printf("-");   gotoxy(i, 0);   printf("-");   }   for (int i = 0; i < HEIGHT-3; i++) //输出左右两面墙   {   gotoxy(0, i);   printf("|");   gotoxy(99, i);   printf("|");   }   gotoxy(24, 28);   printf("得分: 0  生命: %d  时间: 0  ",LIFE);    //xy 30,28可用得分数值 14个空格  }      int foodx, foody;  //食物位置坐标    void sjcsswhs()  //随机产生一个食物  {   srand(time(NULL));      foodx = rand() % (WIDTH - 4) + 2; //使用宏运算随机数最大值需要加括号     while (foodx % 2)   //如果食物的x坐标不是偶数,再获取一个x坐标   {   foodx = rand() % (WIDTH - 4) + 2; //宽度   }     foody = rand() % (HEIGHT - 7) + 3; //高度     gotoxy(foodx, foody);   printf("★");  }    snake* head; //蛇头指针    void cshs()   //初始化蛇的位置  {    snake *tail;  //蛇尾指针   int i;     tail = (snake*)malloc(sizeof(snake));   tail->next = NULL;   tail->x = HEIGHT-6;   tail->y = 8;     //贪吃蛇初始长度5 SNAKEN   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;   }  }    int status = R;  //蛇前进状态    snake* p = NULL; //工作指针  snake* nexthead; //下一个蛇头  int score = 0;  //得分    void snakemove() //蛇前进,上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;   }  }    void czfxhs()   //操作方向函数,接收从键盘输入的按键,控制贪吃蛇行进方向  {   char ch = _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; //空格暂停   }  }    int yxjstjjsmz_1()   //生命掉落条件1咬自己  {   snake* self = head->next; //self为蛇身上的一个结点   while (self)   {   if (self->x == head->x && self->y == head->y) //head和self的成员作比较,蛇头一直存在,这里遍历的是蛇身   {    return 1;   }   self = self->next;   }   return 0;  }    int yxjstjjsmz_2()   //生命掉落条件2碰墙  {   if (head->x <= 1 || head->x >= 98 || head->y <= 0 || head->y >= 26)   return 1;      return 0;  }    int i = LIFE - 1;   //变量存储生命次数    void qcsytmslbhs()   //清除并释放上一条蛇留下来的痕迹,更新生命信息  {   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("--");   }   else if (_x_ == WIDTH - 2)   {   gotoxy(_x_+1, _y_);   printf("|");   }   else if(_x_ == 0)   {   gotoxy(_x_, _y_);   printf("|");   }  }    void sbjsjmhs()   //失败结束界面  {   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);  }    int updatetime()   //获取一次电脑现在的时间  {   int now;   SYSTEMTIME system_time;     GetLocalTime(&system_time);   now = system_time.wMinute * 60 + system_time.wSecond;    return now;  }    int time_1 = updatetime();   //保存游戏刚开始的时间    void gametime()    //写在每次循环之内  {   int time_2 = updatetime() - time_1; //更新游戏开始后时间,用现在的时间减去刚开始的时间   gotoxy(72, 28);   printf("%d s", time_2);  }    int main()//主函数  {   system("mode con cols=100 lines=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();     //失败结束界面     return 0;  }    void HideCursor()  {   CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };   SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);  }    void gotoxy(int x, int y)  {   COORD pos = { x,y };   SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);  }

不足之处:

因为这是我第一次使用链表做一个完整的小程序,所以对链表的运用还很稚嫩,在代码规范和严谨性上面还有很多问题。

另外关于“食物如果刷新到蛇身上则再随机产生一个食物”(172行)相关代码,我不是很确定到底完不完善。

作为一名c语言新手,我对未知的知识始终抱有学习和谦卑的态度,如有贵人能够对我的程序提出建议,我将不胜感激。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

—-想了解C语言单链表贪吃蛇小游戏分享!全部内容且更多的C语言教程关注<计算机技术网(www.ctvol.com)!!>

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/483683.html

(0)
上一篇 2020年11月10日
下一篇 2020年11月10日

精彩推荐