【C语言】基于C语言实现的贪吃蛇游戏

2024-06-01 1106阅读

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏

🔥个人主页:大白的编程日记

🔥专栏:C语言学习之路

【C语言】基于C语言实现的贪吃蛇游戏


文章目录

  • 【C语言】基于C语言实现的贪吃蛇游戏
    • 前言
    • 一.最终实现效果
    • 一.Win32 API介绍
      • 1.1Win32 API
      • 1.2控制台程序
      • 1.3控制台屏幕上的坐标COORD
      • 1.4GetStdHandle
      • 1.5GetConsoleCursorInfo
      • 1.6SetConsoleCursorInfo
      • 1.7SetConsoleCursorPosition
      • 1.8GetAsyncKeyState
      • 二.C语言的国际化
        • 2.1国际化
        • 2.2本地化
        • 2.3类项
        • 2.4setlocale函数
        • 2.5宽字符的打印
        • 三.思路分析
        • 四.GameStar函数
          • 4.1设置控制台信息
          • 4.2欢迎界面的打印
          • 4.3地图的绘制
          • 4.4初始化贪吃蛇
          • 五.GameRun函数
            • 5.1提示信息函数
            • 5.2打印分数
            • 5.3检测键值
            • 5.4蛇的移动
            • 5.5检测是否撞墙
            • 六.GameEnd函数
            • 七.游戏主体设计
            • 八.源码
            • 后言

              前言

              哈喽,各位小伙伴大家好!今天给大家带来的是使用C语言实现的贪吃蛇小游戏。也是检验C语言是否学好的试金石。话不多说,咱们进入正题!向大厂冲锋!

              【C语言】基于C语言实现的贪吃蛇游戏

              一.最终实现效果

              贪吃蛇实现视频

              一.Win32 API介绍

              本次实现贪吃蛇会使用到的⼀些Win32 API知识,接下来我们就学习⼀下什么是Win32 API。

              1.1Win32 API

              Windows 这个多作业系统除了协调应⽤程序的执行、分配内存、管理资源之外,

              它同时也是⼀个很大的服务中心,调用这个服务中心的各种服务(每⼀种服务就是⼀个函数),可以帮应用程序达到开启视窗、描绘图形、使⽤周边设备等目的,由于这些函数服务的对象是应⽤程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。

              WIN32 API也就是Microsoft Windows32位平台的应用程序编程接口。

              1.2控制台程序

              【C语言】基于C语言实现的贪吃蛇游戏

              平常我们运行起来的黑框程序其实就是控制台程序。

              那这个控制台的大小我们可不可设置呢?其实是能的。

              • 设置大小

                我们可以使用cmd命令来设置控制台窗口的长宽:设置控制台窗口的大小,30行,100列。

                mode con cols=100 lines=30
                

                我们要设置控制台的话就需要使用system函数,system函数可以用来执行系统命令。

                int main()
                {
                	system("mode con cols=40 lines=40");
                	return 0;
                }
                

                【C语言】基于C语言实现的贪吃蛇游戏

                【C语言】基于C语言实现的贪吃蛇游戏

                • 设置名字

                  控制台的名字也能修改,使用title命令即可

                  title 贪吃蛇
                  
                  int main()
                  {
                  	system("mode con cols=100 lines=30");
                  	system("title 贪吃蛇");
                  	getchar();
                  	return 0;
                  }
                  

                  【C语言】基于C语言实现的贪吃蛇游戏

                  • 控制台设置

                    我们平时的默认是控制台终端,但是它实现不了我们想要的效果,所以我们要修改一下。

                    【C语言】基于C语言实现的贪吃蛇游戏

                    先点箭头后出现的设置

                    【C语言】基于C语言实现的贪吃蛇游戏

                    之后找到默认终端程序应用,改为控制台主机即可。

                    1.3控制台屏幕上的坐标COORD

                    我们的贪吃蛇游戏里面有蛇,食物,墙等等。他们涉及到的位置是我们游戏中的关键信息,那我们再屏幕上也要定位他们的位置,那怎么定位呢?这就涉及到COORD了。

                    COORD是WindowsAPI中定义的⼀个结构体,表示一个字符在控制台屏幕幕缓冲区上的坐标,坐标系(0,0)的原点位于缓冲区的顶部左侧单元格。

                    【C语言】基于C语言实现的贪吃蛇游戏

                    COORD是一种结构体类型

                    • 结构体类型
                      typedef struct _COORD {
                       SHORT X;
                       SHORT Y;
                      } COORD, *PCOORD;
                      
                      • 头文件

                        使用COORD结构体需要包含windows.h的头文件

                        那现在我们定义一个坐标就可以这样写

                        	COORD pos = { 2,3 };
                        	COORD pos1 = { 5,6 };
                        

                        1.4GetStdHandle

                        GetStdHandle是⼀个WindowsAPI函数。它用于从⼀个特定的标准设备(标准输入、标准输出或标准错误)中取得⼀个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。

                        我们在控制台窗口中进行光标隐藏等操作时,都需要先获得这个窗口。而GetStdHandle就可以获得一个对窗口操作的把手,也就是句柄。通过这个把手我们就可以对控制台窗口进行操作。

                        HANDLE GetStdHandle(DWORD nStdHandle);
                        

                        【C语言】基于C语言实现的贪吃蛇游戏

                        • 参数

                          标准设备。 此参数的取值可为下列值之一。

                          【C语言】基于C语言实现的贪吃蛇游戏

                          那我们贪吃蛇进行蛇的移动,食物的绘制等都是在屏幕上输出信息。所以我们需要或许标准输出设备的句柄

                          	HANDLE houtput = NULL;
                          	houtput=GetStdHandle(STD_OUTPUT_HANDLE);
                          

                          1.5GetConsoleCursorInfo

                          【C语言】基于C语言实现的贪吃蛇游戏

                          大家可以发现我们运行时窗口会有一个光标闪烁,那等下贪吃蛇运行时我们是不希望它闪烁的,有没有办法把它隐藏掉呢?那我们得先获取光标信息。

                          GetConsoleCursorInfo是检索有关指定控制台屏幕缓冲区的光标大小可见性的信息的函数

                          【C语言】基于C语言实现的贪吃蛇游戏

                          它的参数有两个:

                          【C语言】基于C语言实现的贪吃蛇游戏

                          • 光标控制台句柄

                            第一个参数是一个跟光标关联的控制台窗口的句柄

                             _In_  HANDLE               hConsoleOutput,
                            
                            • 光标信息

                              第二个参数是指向光标信息结构体CONSOLE_CURSOR_INFO的指针

                               _Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
                              
                              • 光标信息结构体

                                dwSize,由光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会变化,范围从完全填充单元格到单元底部的水平线条

                                bVisible,游标的可见性。如果光标可见,则此成员为TRUE。

                                【C语言】基于C语言实现的贪吃蛇游戏

                                那我们现在获取光标就可以这样写

                                HANDLE hOutput = NULL;
                                //获取标准输出的句柄(⽤来标识不同设备的数值) 
                                hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                                CONSOLE_CURSOR_INFO CursorInfo={0};//光标信息结构体
                                GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 
                                

                                现在我们输出一下光标的信息看一下

                                	//获取标准输出的句柄(⽤来标识不同设备的数值) 
                                	HANDLE hOutput = NULL;
                                	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                                	CONSOLE_CURSOR_INFO CursorInfo = { 0 };//光标信息结构体
                                	GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 
                                	printf("%d", CursorInfo.dwSize);
                                

                                【C语言】基于C语言实现的贪吃蛇游戏

                                现在我们把光标大小设为50

                                HANDLE hOutput = NULL;
                                hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                                CONSOLE_CURSOR_INFO CursorInfo = { 0 };//光标信息结构体
                                GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 
                                CursorInfo.dwSize = 50;
                                

                                【C语言】基于C语言实现的贪吃蛇游戏

                                可是为什么光标大小没变呢?

                                这是因为我们只修改了光标的信息,我们还需要设置修改后光标信息。

                                1.6SetConsoleCursorInfo

                                SetConsoleCursorInfo是用来设置指定控制台屏幕缓冲区的光标的大小和可见性。

                                • 参数
                                  BOOL WINAPI SetConsoleCursorInfo(
                                    _In_       HANDLE              hConsoleOutput,
                                    _In_ const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
                                  );
                                  

                                  【C语言】基于C语言实现的贪吃蛇游戏

                                  它的参数和GetConsoleCursorInfo一样。

                                  现在我们来设置光标信息

                                  • 修改光标大小

                                    【C语言】基于C语言实现的贪吃蛇游戏

                                  • 隐藏光标

                                    【C语言】基于C语言实现的贪吃蛇游戏

                                    1.7SetConsoleCursorPosition

                                    那我们如何让光标移动到指定位置呢?

                                    设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。

                                    • 参数

                                      一个是控制台窗口的句柄 一个是光标位置的结构体

                                      BOOL WINAPI SetConsoleCursorPosition(
                                       HANDLE hConsoleOutput,
                                       COORD pos
                                      );
                                      

                                      那我们现在想定位光标到第10行,第5列就可以这样写。

                                      COORD pos = { 10, 5};
                                       HANDLE hOutput = NULL;
                                       //获取标准输出的句柄(⽤来标识不同设备的数值) 
                                       hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                                       //设置标准输出上光标的位置为pos 
                                       SetConsoleCursorPosition(hOutput, pos);
                                      

                                      【C语言】基于C语言实现的贪吃蛇游戏

                                      为了方便我们后面游戏打印食物和移动蛇的位置,我们封装⼀个设置光标位置的函数

                                      //设置光标的坐标 
                                      void SetPos(short x, short y)
                                      {
                                         COORD pos = { x, y };
                                         HANDLE hOutput = NULL;
                                         //获取标准输出的句柄(⽤来标识不同设备的数值) 
                                         hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                                        //设置标准输出上光标的位置为pos 
                                         SetConsoleCursorPosition(hOutput, pos);
                                      }
                                      

                                      1.8GetAsyncKeyState

                                      我们贪吃蛇游戏需要根据键盘的的按键进行上下左右的移动。 那如何让程序获取我们的按键信息呢?

                                      这时就需要用到GetAsyncKeyState函数

                                      将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。

                                      GetAsyncKeyState的返回值是short类型,在上⼀次调用GetAsyncKeyState 函数后,如果返回的16位的short数据中,最高 位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。 如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.

                                      • 参数

                                        函数的参数是一个int类型,代表要检测按键的虚拟键值

                                        SHORT GetAsyncKeyState(
                                          [in] int vKey
                                        );
                                        
                                        • 虚拟键值表

                                          【C语言】基于C语言实现的贪吃蛇游戏

                                          这样我们就可以定义一个宏来检测按键是否被按过,只需检测函数返回值的最低位即可。

                                          #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
                                          

                                          【C语言】基于C语言实现的贪吃蛇游戏

                                          二.C语言的国际化

                                          在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印食物使用宽字符★ 普通的字符是占⼀个字节的,这类宽字符是占用2个字节。

                                          这⾥再简单的讲⼀下C语言的国际化特性相关的知识,过去C语言并不适合非英语国家(地区)使用。C语言最初假定字符都是单字节的。但是这些假定并不是在世界的任何地方都适用。

                                          2.1国际化

                                          C语言字符默认是采⽤ASCII编码的,ASCII字符集采⽤的是单字节编码,且只使用了单字节中的低7 位,最高位是没有使用的,可表⽰为0xxxxxxxx;可以看到,ASCII字符集共包含128个字符,在英语国家中,128个字符是基本够用的,但是,在其他国家语言中,比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,⼀些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。

                                          比如,法语中的é的编码为130(⼆进制10000010)。这样⼀来,这些欧洲国家使⽤的编码体系,可以表示最多256个符号。但是,这⾥又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码⽅式,代表的字母却不⼀样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字⺟Gimel在俄语编码中又会代表另⼀个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是⼀样的,不⼀样的只是128–255的这一段。

                                          至于亚洲国家的文字,使⽤的符号就更多了,汉字就多达10万左右。⼀个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达⼀个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示⼀个汉字,所以理论上最多可以表示256x25=65536个符号。

                                          后来为了使C语言适应国际化,C语言的标准中不断加入了国际化的支持。比如:加入了宽字符的类型wchar_t 和宽字符的输⼊和输出函数,加⼊了头文件,其中提供了允许程序员针对特定地区(通常是国家或者说某种特定语⾔的地理区域)调整程序行为的函数。

                                          2.2本地化

                                          提供的函数用于控制C标准库中对于不同的地区会产生不⼀样行为的部分。

                                          在标准中,依赖地区的部分有以下几项:

                                          • 数字量的格式
                                          • 货币量的格式
                                          • 字符集
                                          • 日期和时间的表示形式

                                            2.3类项

                                            通过修改地区,程序可以改变它的行为来适应世界的不同区域。但地区的改变可能会影响库的许多部分,其中⼀部分可能是我们不希望修改的。所以C语言支持针对不同的类项进行修改,下面的⼀个宏,指定⼀个类项:

                                            • LC_COLLATE:影响字符串比较函数 strcoll() 和 strxfrm()
                                            • LC_CTYPE:影响字符处理函数的行为。
                                            • LC_MONETARY:影响货币格式。
                                            • LC_NUMERIC:影响 printf() 的数字格式。
                                            • LC_TIME:影响时间格式 strftime() 和 wcsftime() 。
                                            • LC_ALL-针对所有类项修改,将以上所有类别设置为给定的语⾔环境。

                                              2.4setlocale函数

                                              setlocale函数⽤于修改当前地区,可以针对一个类项修改,也可以针对所有类项。setlocale的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参数是LC_ALL,就会影响所有的类项。

                                              C标准给第⼆个参数仅定义了2种可能取值:“C”(正常模式)和""(本地模式)。

                                              • 正常模式

                                                在任意程序执行开始,都会隐藏式执行调用:

                                                setlocale(LC_ALL, "C");
                                                

                                                地区设置为"C"时,库函数按正常方式执行,小数点是⼀个点

                                                • 本地模式

                                                  当程序运行起来后想改变地区,就只能显示调用setlocale函数。⽤"作为第2个参数,调用setlocale函数就可以切换到本地模式,这种模式下程序会适应本地环境。

                                                  比如:切换到我们的本地模式后就支持宽字符(汉字)的输出等。

                                                  setlocale(LC_ALL, " ");//切换到本地环境 
                                                  

                                                  2.5宽字符的打印

                                                  那如果想在屏幕上打印宽字符,怎么打印呢?

                                                  宽字符的字面量必须加上前缀“L”,否则C语言会把字面量当作窄字符类型处理。前缀“L”在单引

                                                  号前面,表⽰宽字符,对应 wprintf() 的占位符为 %lc ;在双引号前⾯,表示宽字符串,对应

                                                  wprintf() 的占位符为 %ls 。

                                                  #include 
                                                  #include
                                                  int main() {
                                                   setlocale(LC_ALL, "");
                                                   wchar_t ch1 = L'●'; 
                                                   wchar_t ch2 = L'⽐';
                                                   wchar_t ch3 = L'特';
                                                   wchar_t ch4 = L'★';
                                                   
                                                   printf("%c%c\n", 'a', 'b');
                                                   
                                                   wprintf(L"%lc\n", ch1);
                                                   wprintf(L"%lc\n", ch2);
                                                   wprintf(L"%lc\n", ch3);
                                                   wprintf(L"%lc\n", ch4);
                                                   return 0;
                                                  }
                                                  

                                                  【C语言】基于C语言实现的贪吃蛇游戏

                                                  三.思路分析

                                                  我们先把游戏分为三个大的模块。每个模块分别负责不同的功能。 每个模块具体实现又由多个小的函数模块合理设计拼接后组成。大体的思路如下:

                                                  【C语言】基于C语言实现的贪吃蛇游戏

                                                  • GameStar函数

                                                    GameStar函数负责进入窗口大小和名字的设置,光标的隐藏。

                                                    欢迎界面的打印,地图的绘制。

                                                    贪吃蛇的创建和初始化,食物的创建。

                                                  • GameRun函数

                                                    右侧打印帮助信息-PrintHelpInfo

                                                    打印当前已获得分数和每个食物的分数以提示用户

                                                    根据按键情况移动蛇-SnakeMove直到游戏是结束状态

                                                  • SnakeMove

                                                    根据蛇头的坐标和方向,计算下⼀个节点的坐标

                                                    判断下⼀个节点是否是食物-NextIsFood

                                                    是食物就吃掉-EatFood

                                                    不是食物,吃掉食物,尾巴删除⼀节-NoFood

                                                    判断是否撞墙-KillByWall

                                                    判断是否撞上自己-KillBySelf

                                                  • GameEnd

                                                    告知游戏结束的原因

                                                    释放蛇身节点

                                                    四.GameStar函数

                                                    为了方便阅读代码,这里先把我们定义好的宏给大家看

                                                    【C语言】基于C语言实现的贪吃蛇游戏

                                                    • 实现效果

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      4.1设置控制台信息

                                                      首先我们需要设置控制台大小,名字,还要隐藏光标。

                                                      这些操作我们前面讲过的了。不再过多赘述了。

                                                      system("mode con cols=100 lines=30");//设置控制台窗口大小
                                                      system("title 贪吃蛇");//设置控制台名字
                                                      HANDLE houtput = NULL;
                                                      houtput = GetStdHandle(STD_OUTPUT_HANDLE);
                                                      //定义一个光标信息的结构体
                                                      CONSOLE_CURSOR_INFO cursor_info ;
                                                      //获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中
                                                      GetConsoleCursorInfo(houtput, &cursor_info);
                                                      //修改光标(隐藏光标)
                                                      cursor_info.bVisible= false;
                                                      //设置和houtput句柄相关的控制台上的光标信息
                                                      SetConsoleCursorInfo(houtput, &cursor_info);
                                                      

                                                      4.2欢迎界面的打印

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      这里我们把欢迎界面的打印封装为WelcomeToSnake函数

                                                      我们只需要将光标定位到指定位置,然后打印文字即可。

                                                      注意这里涉及到程序的暂停我们用system函数即可实现。

                                                      打印完切换下一个界面时,我们清理屏幕。这个用system函数也能实现

                                                      再定位打印文字。

                                                      void WelcomeToSnake()
                                                      {
                                                      	setpos(40, 14);//定位光标
                                                      	wprintf(L"欢迎来到贪吃蛇小游戏~\n");
                                                      	setpos(42, 20);//定位光标
                                                      	system("pause");//暂停程序
                                                      	system("cls");//清理屏幕
                                                      	setpos(25, 14);//定位光标
                                                      	wprintf(L"分别用↑.↓.←.→控制移动方向,F3加速,F4减速\n");
                                                      	setpos(25, 15);//定位光标
                                                      	wprintf(L"加速能够获得更高的分数\n");
                                                      	setpos(42, 20);//定位光标
                                                      	system("pause");//暂停程序
                                                      	system("cls");//清理屏幕
                                                      }
                                                      

                                                      4.3地图的绘制

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      地图的绘制我们也单独封装为一个Greatmap()函数

                                                      假设我们要绘制一个27行 58列的地图,我们只需要关注好四个角落点的坐标,

                                                      然后用四层for循环打印即可。

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      void Greatmap()
                                                      {
                                                      	setpos(0, 0);//定位原点
                                                      	for (int i = 0; i y == y)
                                                      			goto again;//食物和蛇身重叠重新生成
                                                      		pcur = pcur->next;
                                                      	}
                                                      	fool->x = x;//赋值横坐标
                                                      	fool->y = y;//赋值纵坐标
                                                      	fool->next = NULL;//置空
                                                      	setpos(fool->x, fool->y);//定位光标
                                                      	wprintf(L"%lc", FOOD);//打印食物
                                                      	ps->snakefool= fool;//存放食物节点
                                                      }
                                                      

                                                      最后我们再循环创建五个初始的蛇身节点,初始化贪吃蛇信息,再创建食物即可。

                                                      void Initsnake(psnake ps)
                                                      {
                                                      	psnake pcur = ps;
                                                      	for (int i = 0; i next = NULL;
                                                      		node->x = POS_X + 2 * i;//横坐标
                                                      		node->y = POS_Y;//纵坐标
                                                      		if (pcur->shead == NULL)
                                                      		{
                                                      			pcur->shead = node;//蛇头节点(第一个节点)
                                                      		}
                                                      		else
                                                      		{
                                                      			node->next = pcur->shead;//头插法
                                                      			pcur->shead = node;
                                                      		}
                                                      		while (node)//遍历蛇身打印
                                                      		{
                                                      			setpos(node->x, node->y);//定位蛇身坐标
                                                      			wprintf(L"%lc", BODY);//打印
                                                      			node = node->next;//遍历下一个蛇身节点
                                                      		}
                                                      	}
                                                      	ps->dir = right;//默认移动方向为右
                                                      	ps->statu = ok;//游戏状态正常
                                                      	ps->fool_score = 10;//默认食物分数为10
                                                      	ps->score = 0;//总分为0
                                                      	ps->sleep_time = 200;//休眠时间默认为0
                                                      	GreatFool(ps);//创建食物
                                                      }
                                                      

                                                      五.GameRun函数

                                                      5.1提示信息函数

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      在游戏时我们打印一下提示信息给玩家。封装PrintHelpInfo()

                                                      void PrintHelpInfo()//打印提示信息
                                                      {
                                                      	setpos(64, 15);
                                                      	wprintf(L"不能穿墙,不能咬到⾃⼰\n");
                                                      	setpos(64, 16);
                                                      	printf("分别用↑.↓.←.→分别控制蛇的移动\n");
                                                      	setpos(64, 17);
                                                      	wprintf(L"F3 为加速,F4 为减速\n");
                                                      	setpos(64, 18);
                                                      	wprintf(L"ESC :退出游戏.space:暂停游戏.");
                                                      	setpos(64, 19);
                                                      	wprintf(L"成杰MAKE");
                                                      }
                                                      

                                                      5.2打印分数

                                                      【C语言】基于C语言实现的贪吃蛇游戏

                                                      游戏过程食物分数和总得分都需要更新

                                                      我们也要打印出来。

                                                      setpos(64, 10);//定位
                                                      printf("总分:%2d", ps->score);//打印信息
                                                      setpos(64, 11);//定位
                                                      printf("当前食物分数:%2d", ps->fool_score);//打印信息
                                                      

                                                      5.3检测键值

                                                      游戏过程我们需要根据键盘输入进行相对的相应

                                                      蛇的移动,暂停 加速减速等。

                                                      我们前面已经定义了一个宏,直接使用即可

                                                      #define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )//检测虚拟键值
                                                      if (KEY_PRESS(VK_UP) && ps->dir!=down)//按键向上同时当前方向不能为下
                                                      {
                                                      	ps->dir = up;//设置移动方向
                                                      }
                                                      else if (KEY_PRESS(VK_DOWN) && ps->dir != up)//按键向下同时当前方向不能为上
                                                      {
                                                      	ps->dir = down;//设置移动方向
                                                      }
                                                      else if (KEY_PRESS(VK_LEFT) && ps->dir != right)//按键向左同时当前方向不能为右
                                                      {
                                                      	ps->dir = left;//设置移动方向
                                                      }
                                                      else if (KEY_PRESS(VK_RIGHT) && ps->dir != left)//按键向右同时当前方向不能为左
                                                      {
                                                      	ps->dir = right;//设置移动方向
                                                      }
                                                      else if (KEY_PRESS(VK_ESCAPE))//检测ESC按键
                                                      {
                                                      	ps->statu = end;//设置退出游戏状态
                                                      }
                                                      else if (KEY_PRESS(VK_SPACE) )//检测space按键
                                                      {
                                                      	Pause();//暂停游戏
                                                      }
                                                      else if (KEY_PRESS(VK_F3))//检车f3加速按键
                                                      {
                                                      	if (ps->sleep_time > 120)//设置加速上限
                                                      	{
                                                      		ps->sleep_time -= 20;//减少休眠加快速度
                                                      		ps->fool_score += 2;//分数增加
                                                      	}
                                                      }
                                                      else if (KEY_PRESS(VK_F4))//检测f4减速按键
                                                      {
                                                      	if (ps->fool_score> 2)//设置减速上限
                                                      	{
                                                      		ps->sleep_time += 20;//增加休眠时间减慢速度
                                                      		ps->fool_score -= 2;//分数减少
                                                      	}
                                                      }
                                                      

                                                      注意我们移动时不能与当前移动方向相反。

                                                      加速减速我们加减休眠时间即可。

                                                      暂停我们用pause函数即可,检测space按键,按过直接break跳出即可。

                                                      否则一直休眠。

                                                      void Pause()
                                                      {
                                                      	while (1)
                                                      	{
                                                      		Sleep(200);//休眠
                                                      		if (KEY_PRESS(VK_SPACE))//检测是否再次按space按键
                                                      		{
                                                      			break;//继续游戏
                                                      		}
                                                      	}
                                                      }
                                                      

                                                      检测完后我们再根据按键输入进行蛇的移动即可。

                                                      我们封装为Snakemove函数。

                                                      我们先创建一个节点作为下一个蛇头节点。

                                                      然后根据移动方向给节点横纵坐标赋值即可。

                                                      pSnakenode pcur = (pSnakenode)malloc(sizeof(Snakenode));//生成蛇头下一个位置的节点
                                                      if (pcur == NULL)//判空
                                                      {
                                                      	perror("Snakemove:malloc");
                                                      	return; 
                                                      }
                                                      switch (ps->dir)//检测蛇移动方向
                                                      {
                                                      case up:
                                                      	pcur->y=ps->shead->y -1;//赋值横坐标
                                                      	pcur->x = ps->shead->x;//赋值纵坐标
                                                      	break;
                                                      case down:
                                                      	pcur->y = ps->shead->y +1;//赋值横坐
                                                      	pcur->x = ps->shead->x; // 赋值纵坐标
                                                      	break;
                                                      case right:
                                                      	pcur->x = ps->shead->x +2;//赋值横坐
                                                      	pcur->y = ps->shead->y; // 赋值纵坐标
                                                      	break;
                                                      case left:
                                                      	pcur->x = ps->shead->x -2;//赋值横坐
                                                      	pcur->y = ps->shead->y; // 赋值纵坐标
                                                      	break;
                                                      }
                                                      

                                                      5.4蛇的移动

                                                      蛇的移动分两种情况:

                                                      • 吃食物移动

                                                        若下一个位置是食物。

                                                        我们释放开辟的节点,然后让食物节点成为新的蛇头节点

                                                        然后遍历打印蛇身,再创建新的食物即可。同时更新得分。

                                                        void EatFood(pSnakenode pn, psnake ps)//吃食物
                                                        {
                                                        	ps->snakefool->next = ps->shead;//食物节点链接蛇头
                                                        	ps->shead = ps->snakefool;//食物节点成为蛇头
                                                        	free(pn);//释放新开辟的蛇头节点
                                                        	pn = NULL;
                                                        	pSnakenode cur = ps->shead;
                                                        	while (cur)//遍历打印蛇身
                                                        	{
                                                        		setpos(cur->x, cur->y);
                                                        		wprintf(L"%lc", BODY);
                                                        		cur = cur->next;
                                                        	}
                                                        	ps->score += ps->fool_score;//总分增加
                                                        	GreatFool(ps);//生成新的食物
                                                        }
                                                        
                                                        • 不吃食物移动

                                                          让新开辟节点链接原来的蛇头,新开辟的节点成为新的蛇头。

                                                          再遍历找到倒数第二个尾节点,释放尾巴节点,再让倒数第二个节点指向空封尾。同时记得打印空白覆盖掉蛇尾节点打印的信息。再遍历打印蛇身即可。

                                                          void NotFood(pSnakenode pn, psnake ps)
                                                          {
                                                          	pn->next = ps->shead;//让新的蛇头连接原来的蛇头
                                                          	ps->shead = pn;//让蛇下一个位置的节点成为新的蛇头
                                                          	pSnakenode pcur = ps->shead;
                                                          	while (pcur->next->next != NULL)//找到蛇尾倒数第二个节点
                                                          	{
                                                          		pcur = pcur->next;//移动
                                                          	}
                                                          	pSnakenode dle = pcur;
                                                          	setpos(pcur->next->x, pcur->next->y);//定位光标到最后的蛇尾
                                                          	printf("  ");//覆盖原来蛇尾打印的信息
                                                          	free(dle->next);//释放最后的蛇尾节点
                                                          	dle->next = NULL;
                                                          	pSnakenode cur = pn;
                                                          	while (cur)
                                                          	{
                                                          		setpos(cur->x, cur->y);
                                                          	    wprintf(L"%lc", BODY);
                                                          		cur = cur->next;
                                                          	}
                                                          }
                                                          

                                                          5.5检测是否撞墙

                                                          我们只需要检测横坐标是否为0或56

                                                          纵坐标是否为0或26。

                                                          再根据穿墙的横坐标或纵坐标不变,修改蛇头另一变化坐标即可。

                                                          最后即可设置游戏状态即可。

                                                          要实现穿墙我们再让蛇每次移动都刷新城墙即可。

                                                          【C语言】基于C语言实现的贪吃蛇游戏

                                                          void KillByWall(psnake ps)
                                                          {
                                                          	if (ps->shead->x == 56)//检测是否撞到第二列城墙
                                                          	{
                                                          		ps->shead->x = 0;//重新定位穿墙后的横坐标位置(第一列出)
                                                          	}
                                                          	else if (ps->shead->x == 0)//检测是否撞到第一列城墙
                                                          	{
                                                          		ps->shead->x = 56;//重新定位穿墙后的横坐标位置(第二列出)
                                                          	}
                                                          	else if (ps->shead->y == 0)//检测是否撞到第一行城墙
                                                          	{
                                                          		ps->shead->y = 26;//重新定位穿墙后的纵坐标位置(第一行出)
                                                          	}
                                                          	else if (ps->shead->y == 26)//检测是否撞到第二行城墙
                                                          	{
                                                          		ps->shead->y = 0;//重新定位穿墙后的纵坐标位置(第二行出)
                                                          	}
                                                          }
                                                          
                                                          • 检测是否咬到自己

                                                            我们只需要判断当前蛇头坐标是否与其他蛇身坐标重合即可。

                                                            用循环遍历蛇身在判断即可。最后即可设置游戏状态即可

                                                            void KillBySelf( psnake ps)
                                                            {
                                                            	pSnakenode pcur = ps->shead->next;//保存蛇头下一个节点
                                                            	while (pcur)//遍历蛇身
                                                            	{
                                                            		if (ps->shead->x == pcur->x && ps->shead->y == pcur->y)//蛇身与蛇头重合
                                                            		{
                                                            			ps->statu = kill_by_self;//设置游戏状态
                                                            			break;//结束循环
                                                            		}
                                                            		pcur = pcur->next;//移动
                                                            	}
                                                            }
                                                            

                                                            每次移动后都检测撞墙和咬到自己。

                                                            判断游戏状态,正常则继续游戏。

                                                            六.GameEnd函数

                                                            游戏结束我们需要检测游戏状态再打印对应提示信息。

                                                            最后循环遍历销毁蛇身节点和食物节点即可

                                                            void GemaEnd(psnake ps)
                                                            {
                                                            	pSnakenode pcur = ps->shead;
                                                            	setpos(20, 12);//定位光标
                                                            	switch (ps->statu)//游戏状态
                                                            	{
                                                            	case kill_by_wall://撞墙
                                                            		wprintf(L"您撞到墙上,游戏结束!");
                                                            		break;
                                                            	case kill_by_self://咬到自己
                                                            		wprintf(L"您咬到自己,游戏结束!");
                                                            		break;
                                                            	case end://自己结束
                                                            		wprintf(L"您主动结束了游戏!");
                                                            		break;
                                                            	}
                                                            	setpos(0, 27);//定位光标
                                                            	while (pcur)//遍历蛇身销毁链表
                                                            	{
                                                            		pSnakenode del = pcur;//保存销毁节点
                                                            		pcur = pcur->next;//移动下一个销毁节点
                                                            		free(del);//销毁
                                                            		del = NULL;
                                                            	}
                                                            	free(ps->snakefool);//销毁食物
                                                            	ps->snakefool = NULL;
                                                            } 
                                                            

                                                            七.游戏主体设计

                                                            最后我们调用三大模块函数即可,再用do_while循环给用户选择是否继续再来一局游戏的选择。注意使用宽字符要记得本地化。

                                                            setlocale(LC_ALL, "");
                                                            void test()
                                                            {
                                                            	char ch = 0;
                                                            	do
                                                            	{
                                                            		Snake snake = { 0 };
                                                            		GemeStar(&snake);
                                                            		GameRun(&snake);
                                                            		GemaEnd(&snake);
                                                            		setpos(20, 15);
                                                            		wprintf(L"再来一局吗?(Y/N):");
                                                            		ch = getchar();
                                                            		setpos(0, 27);
                                                            	} while (ch == 'Y' || ch == 'y');
                                                            }
                                                            

                                                            八.源码

                                                            • Snake.h
                                                              #pragma once
                                                              #include
                                                              #include
                                                              #include 
                                                              #include
                                                              #include
                                                              #include
                                                              #define WALL L'□'
                                                              #define FOOD L'★'
                                                              #define BODY L'●'
                                                              #define POS_X 24
                                                              #define POS_Y 5
                                                              #define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )//检测虚拟键值
                                                              enum DIRECTION//枚举蛇的方向
                                                              {
                                                              	up = 1,
                                                                  down,
                                                              	left ,
                                                              	right
                                                              };
                                                              enum STATUS//游戏的状态
                                                              {
                                                              	ok = 1,
                                                              	kill_by_wall,
                                                              	kill_by_self,
                                                              	end
                                                              };
                                                              typedef struct SnakeNode //蛇身
                                                              {
                                                              	int x;
                                                              	int y;
                                                              	struct SnakeNode* next;
                                                              }Snakenode,* pSnakenode;
                                                              typedef struct Snake//游戏中贪吃蛇的信息
                                                              {
                                                              	pSnakenode shead;
                                                              	pSnakenode snakefool;
                                                              	enum DRIECTION dir;
                                                              	enum STATUS statu;
                                                              	int fool_score;
                                                              	int score;
                                                              	int sleep_time;
                                                              }Snake,*psnake;
                                                              void setpos(short x,short y);
                                                              void GemeStar(psnake ps);
                                                              void Greatmap();
                                                              void Initsnake(psnake ps);
                                                              void GreatFool(psnake ps);
                                                              void GameRun(psnake ps);
                                                              void PrintHelpInfo();
                                                              void Pause();
                                                              void Snakemove(psnake ps);
                                                              int NextIsFood(pSnakenode pn, psnake ps);
                                                              void EatFood(pSnakenode pn, psnake ps);
                                                              void NotFood(pSnakenode pn, psnake ps);
                                                              void KillByWall(psnake ps);
                                                              void KillBySelf(psnake ps);
                                                              void GemaEnd(psnake ps);
                                                              
                                                              • Snake.c
                                                                #define _CRT_SECURE_NO_WARNINGS 1
                                                                #include"snake.h"
                                                                void WelcomeToSnake()
                                                                {
                                                                	setpos(40, 14);//定位光标
                                                                	wprintf(L"欢迎来到贪吃蛇小游戏~\n");
                                                                	setpos(42, 20);//定位光标
                                                                	system("pause");//暂停程序
                                                                	system("cls");//清理屏幕
                                                                	setpos(25, 14);//定位光标
                                                                	wprintf(L"分别用↑.↓.←.→控制移动方向,F3加速,F4减速\n");
                                                                	setpos(25, 15);//定位光标
                                                                	wprintf(L"加速能够获得更高的分数\n");
                                                                	setpos(42, 20);//定位光标
                                                                	system("pause");//暂停程序
                                                                	system("cls");//清理屏幕
                                                                }
                                                                void GemeStar(psnake ps)
                                                                {
                                                                	system("mode con cols=100 lines=30");//设置控制台窗口大小
                                                                	system("title 贪吃蛇");//设置控制台名字
                                                                	HANDLE houtput = NULL;
                                                                	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
                                                                	//定义一个光标信息的结构体
                                                                	CONSOLE_CURSOR_INFO cursor_info ;
                                                                	//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中
                                                                	GetConsoleCursorInfo(houtput, &cursor_info);
                                                                	//修改光标(隐藏光标)
                                                                	cursor_info.bVisible= false;
                                                                	//设置和houtput句柄相关的控制台上的光标信息
                                                                	SetConsoleCursorInfo(houtput, &cursor_info);
                                                                	WelcomeToSnake();//欢迎界面打印 
                                                                	Greatmap();//地图打印
                                                                	Initsnake(ps);//初始化贪吃蛇的信息
                                                                }
                                                                void Greatmap()
                                                                {
                                                                	setpos(0, 0);//定位原点
                                                                	for (int i = 0; i y = POS_Y;//纵坐标
                                                                		if (pcur->shead == NULL)
                                                                		{
                                                                			pcur->shead = node;//蛇头节点(第一个节点)
                                                                		}
                                                                		else
                                                                		{
                                                                			node->next = pcur->shead;//头插法
                                                                			pcur->shead = node;
                                                                		}
                                                                		while (node)//遍历蛇身打印
                                                                		{
                                                                			setpos(node->x, node->y);//定位蛇身坐标
                                                                			wprintf(L"%lc", BODY);//打印
                                                                			node = node->next;//遍历下一个蛇身节点
                                                                		}
                                                                	}
                                                                	ps->dir = right;//默认移动方向为右
                                                                	ps->statu = ok;//游戏状态正常
                                                                	ps->fool_score = 10;//默认食物分数为10
                                                                	ps->score = 0;//总分为0
                                                                	ps->sleep_time = 200;//休眠时间默认为0
                                                                	GreatFool(ps);//创建食物
                                                                }
                                                                void GreatFool(psnake ps)
                                                                {
                                                                	pSnakenode pcur = ps->shead;
                                                                	pSnakenode fool = (pSnakenode)malloc(sizeof(Snakenode));//创建蛇的节点作为食物节点
                                                                	if (fool == NULL)//判空
                                                                	{
                                                                		perror("GreatFool:malloc");
                                                                		return;
                                                                	}
                                                                	int x, y;
                                                                again:
                                                                	do
                                                                	{
                                                                	   x = rand() % 53 + 2;//生成横坐标
                                                                	   y = rand() % 25 + 1;//纵坐标
                                                                	} while (x % 2 != 0);//保证横坐标为偶数
                                                                	while (pcur)//遍历蛇身
                                                                	{
                                                                		if (pcur->x == x && pcur->y == y)
                                                                			goto again;//食物和蛇身重叠重新生成
                                                                		pcur = pcur->next;
                                                                	}
                                                                	fool->x = x;//赋值横坐标
                                                                	fool->y = y;//赋值纵坐标
                                                                	fool->next = NULL;//置空
                                                                	setpos(fool->x, fool->y);//定位光标
                                                                	wprintf(L"%lc", FOOD);//打印食物
                                                                	ps->snakefool= fool;//存放食物节点
                                                                }
                                                                void PrintHelpInfo()//打印提示信息
                                                                {
                                                                	setpos(64, 15);
                                                                	wprintf(L"不能穿墙,不能咬到⾃⼰\n");
                                                                	setpos(64, 16);
                                                                	printf("分别用↑.↓.←.→分别控制蛇的移动\n");
                                                                	setpos(64, 17);
                                                                	wprintf(L"F3 为加速,F4 为减速\n");
                                                                	setpos(64, 18);
                                                                	wprintf(L"ESC :退出游戏.space:暂停游戏.");
                                                                	setpos(64, 19);
                                                                	wprintf(L"成杰MAKE");
                                                                }
                                                                void Pause()
                                                                {
                                                                	while (1)
                                                                	{
                                                                		Sleep(200);//休眠
                                                                		if (KEY_PRESS(VK_SPACE))//检测是否再次按space按键
                                                                		{
                                                                			break;//继续游戏
                                                                		}
                                                                	}
                                                                }
                                                                int NextIsFood(pSnakenode pn, psnake ps)
                                                                {
                                                                	return (pn->x == ps->snakefool->x &&
                                                                		    pn->y == ps->snakefool->y);//判断下一个节点是否是食物
                                                                }
                                                                void Snakemove(psnake ps)
                                                                {
                                                                	pSnakenode pcur = (pSnakenode)malloc(sizeof(Snakenode));//生成蛇头下一个位置的节点
                                                                	if (pcur == NULL)//判空
                                                                	{
                                                                		perror("Snakemove:malloc");
                                                                		return; 
                                                                	}
                                                                	switch (ps->dir)//检测蛇移动方向
                                                                	{
                                                                	case up:
                                                                		pcur->y=ps->shead->y -1;//赋值横坐标
                                                                		pcur->x = ps->shead->x;//赋值纵坐标
                                                                		break;
                                                                	case down:
                                                                		pcur->y = ps->shead->y +1;//赋值横坐
                                                                		pcur->x = ps->shead->x; // 赋值纵坐标
                                                                		break;
                                                                	case right:
                                                                		pcur->x = ps->shead->x +2;//赋值横坐
                                                                		pcur->y = ps->shead->y; // 赋值纵坐标
                                                                		break;
                                                                	case left:
                                                                		pcur->x = ps->shead->x -2;//赋值横坐
                                                                		pcur->y = ps->shead->y; // 赋值纵坐标
                                                                		break;
                                                                	}
                                                                	if (NextIsFood(pcur, ps))//判断下一个节点是否为食物
                                                                	{
                                                                		EatFood(pcur, ps);//吃食物的移动
                                                                	}
                                                                	else
                                                                	{
                                                                		NotFood(pcur,ps);//不吃食物的移动
                                                                	}
                                                                }
                                                                void GameRun(psnake ps)
                                                                {
                                                                	PrintHelpInfo();//打印提示信息
                                                                	do
                                                                	{
                                                                		setpos(64, 10);//定位
                                                                		printf("总分:%2d", ps->score);//打印信息
                                                                		setpos(64, 11);//定位
                                                                		printf("当前食物分数:%2d", ps->fool_score);//打印信息
                                                                		if (KEY_PRESS(VK_UP) && ps->dir!=down)//按键向上同时当前方向不能为下
                                                                		{
                                                                			ps->dir = up;//设置移动方向
                                                                		}
                                                                		else if (KEY_PRESS(VK_DOWN) && ps->dir != up)//按键向下同时当前方向不能为上
                                                                		{
                                                                			ps->dir = down;//设置移动方向
                                                                		}
                                                                		else if (KEY_PRESS(VK_LEFT) && ps->dir != right)//按键向左同时当前方向不能为右
                                                                		{
                                                                			ps->dir = left;//设置移动方向
                                                                		}
                                                                		else if (KEY_PRESS(VK_RIGHT) && ps->dir != left)//按键向右同时当前方向不能为左
                                                                		{
                                                                			ps->dir = right;//设置移动方向
                                                                		}
                                                                		else if (KEY_PRESS(VK_ESCAPE))//检测ESC按键
                                                                		{
                                                                			ps->statu = end;//设置退出游戏状态
                                                                		}
                                                                		else if (KEY_PRESS(VK_SPACE) )//检测space按键
                                                                		{
                                                                			Pause();//暂停游戏
                                                                		}
                                                                		else if (KEY_PRESS(VK_F3))//检车f3加速按键
                                                                		{
                                                                			if (ps->sleep_time > 120)//设置加速上限
                                                                			{
                                                                				ps->sleep_time -= 20;//减少休眠加快速度
                                                                				ps->fool_score += 2;//分数增加
                                                                			}
                                                                		}
                                                                		else if (KEY_PRESS(VK_F4))//检测f4减速按键
                                                                		{
                                                                			if (ps->fool_score> 2)//设置减速上限
                                                                			{
                                                                				ps->sleep_time += 20;//增加休眠时间减慢速度
                                                                				ps->fool_score -= 2;//分数减少
                                                                			}
                                                                		}
                                                                		Snakemove(ps);//蛇移动
                                                                		Greatmap();//每次移动刷新城墙实现穿墙;
                                                                		Sleep(ps->sleep_time);//休眠
                                                                		KillByWall(ps);//检测是否撞墙
                                                                		KillBySelf(ps);//检测是否咬到自己
                                                                	} while (ps->statu == ok);//检测游戏状态
                                                                }
                                                                void EatFood(pSnakenode pn, psnake ps)//吃食物
                                                                {
                                                                	ps->snakefool->next = ps->shead;//食物节点链接蛇头
                                                                	ps->shead = ps->snakefool;//食物节点成为蛇头
                                                                	free(pn);//释放新开辟的蛇头节点
                                                                	pn = NULL;
                                                                	pSnakenode cur = ps->shead;
                                                                	while (cur)//遍历打印蛇身
                                                                	{
                                                                		setpos(cur->x, cur->y);
                                                                		wprintf(L"%lc", BODY);
                                                                		cur = cur->next;
                                                                	}
                                                                	ps->score += ps->fool_score;//总分增加
                                                                	GreatFool(ps);//生成新的食物
                                                                }
                                                                void NotFood(pSnakenode pn, psnake ps)
                                                                {
                                                                	pn->next = ps->shead;//让新的蛇头连接原来的蛇头
                                                                	ps->shead = pn;//让蛇下一个位置的节点成为新的蛇头
                                                                	pSnakenode pcur = ps->shead;
                                                                	while (pcur->next->next != NULL)//找到蛇尾倒数第二个节点
                                                                	{
                                                                		pcur = pcur->next;//移动
                                                                	}
                                                                	pSnakenode dle = pcur;
                                                                	setpos(pcur->next->x, pcur->next->y);//定位光标到最后的蛇尾
                                                                	printf("  ");//覆盖原来蛇尾打印的信息
                                                                	free(dle->next);//释放最后的蛇尾节点
                                                                	dle->next = NULL;
                                                                	pSnakenode cur = pn;
                                                                	while (cur)
                                                                	{
                                                                		setpos(cur->x, cur->y);
                                                                	    wprintf(L"%lc", BODY);
                                                                		cur = cur->next;
                                                                	}
                                                                }
                                                                void KillByWall(psnake ps)
                                                                {
                                                                	if (ps->shead->x == 56)//检测是否撞到第二列城墙
                                                                	{
                                                                		ps->shead->x = 0;//重新定位穿墙后的横坐标位置(第一列出)
                                                                	}
                                                                	else if (ps->shead->x == 0)//检测是否撞到第一列城墙
                                                                	{
                                                                		ps->shead->x = 56;//重新定位穿墙后的横坐标位置(第二列出)
                                                                	}
                                                                	else if (ps->shead->y == 0)//检测是否撞到第一行城墙
                                                                	{
                                                                		ps->shead->y = 26;//重新定位穿墙后的纵坐标位置(第一行出)
                                                                	}
                                                                	else if (ps->shead->y == 26)//检测是否撞到第二行城墙
                                                                	{
                                                                		ps->shead->y = 0;//重新定位穿墙后的纵坐标位置(第二行出)
                                                                	}
                                                                }
                                                                void KillBySelf( psnake ps)
                                                                {
                                                                	pSnakenode pcur = ps->shead->next;//保存蛇头下一个节点
                                                                	while (pcur)//遍历蛇身
                                                                	{
                                                                		if (ps->shead->x == pcur->x && ps->shead->y == pcur->y)//蛇身与蛇头重合
                                                                		{
                                                                			ps->statu = kill_by_self;//设置游戏状态
                                                                			break;//结束循环
                                                                		}
                                                                		pcur = pcur->next;//移动
                                                                	}
                                                                }
                                                                void GemaEnd(psnake ps)
                                                                {
                                                                	pSnakenode pcur = ps->shead;
                                                                	setpos(20, 12);//定位光标
                                                                	switch (ps->statu)//游戏状态
                                                                	{
                                                                	case kill_by_wall://撞墙
                                                                		wprintf(L"您撞到墙上,游戏结束!");
                                                                		break;
                                                                	case kill_by_self://咬到自己
                                                                		wprintf(L"您咬到自己,游戏结束!");
                                                                		break;
                                                                	case end://自己结束
                                                                		wprintf(L"您主动结束了游戏!");
                                                                		break;
                                                                	}
                                                                	setpos(0, 27);//定位光标
                                                                	while (pcur)//遍历蛇身销毁链表
                                                                	{
                                                                		pSnakenode del = pcur;//保存销毁节点
                                                                		pcur = pcur->next;//移动下一个销毁节点
                                                                		free(del);//销毁
                                                                		del = NULL;
                                                                	}
                                                                	free(ps->snakefool);//销毁食物
                                                                	ps->snakefool = NULL;
                                                                } 
                                                                
                                                                • test.c
                                                                  #define _CRT_SECURE_NO_WARNINGS 1
                                                                  #include"snake.h"
                                                                  void test()
                                                                  {
                                                                  	char ch = 0;
                                                                  	do
                                                                  	{
                                                                  		Snake snake = { 0 };
                                                                  		GemeStar(&snake);
                                                                  		GameRun(&snake);
                                                                  		GemaEnd(&snake);
                                                                  		setpos(20, 15);
                                                                  		wprintf(L"再来一局吗?(Y/N):");
                                                                  		ch = getchar();
                                                                  		setpos(0, 27);
                                                                  	} while (ch == 'Y' || ch == 'y');
                                                                  }
                                                                  int main()
                                                                   {
                                                                  	setlocale(LC_ALL, "");
                                                                  	test();
                                                                  	return 0;
                                                                  }
                                                                  

                                                                  后言

                                                                  这就是用C语言写出来的贪吃蛇小游戏。这游戏基本使用到C语言所学的全部内容。也算是C语言的试金石吧!今天就分享到这里,感谢小伙伴的耐心垂阅!咱们下期见!拜拜~

                                                                  【C语言】基于C语言实现的贪吃蛇游戏

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]