【C语言】贪吃蛇(c语言含源码)

打印 上一主题 下一主题

主题 846|帖子 846|积分 2538


简述

我们要实现一个在控制台上的贪吃蛇,制品是下图这种。

先调解情况

我们可以看到我在控制台上有贪吃蛇名字,怎样实现呢?

起首我们要将我们的vs终端改为Windows控制台主机。步调如下

1)先鼠标右击上图终端的白色边框,当出现选项时。2)左击属性
3)点终端在有下面选择Windows控制台主机。最后如下图

后续就通过函数来调解情况,在后续一步一步讲授
本地化

C语言为顺应国际化就提供了本地模式和尺度模式
setlocale函数

用此函数修改模式
改为本地模式
  1. setlocale(LC_ALL," ");
复制代码
改为尺度模式
  1. setlocale(LC_ALL,"C");
复制代码
宽字符的打印

使用wprintf函数,该函数打印的字符占两个空间,它和printf使用区别在于要在双引号前加上L。
  1. //打印一个字符c
  2. wprintf(L"%c",L'c');
复制代码
但在我写的代码中就算使用了wprintf照旧只占一个空间,因为我的控制台情况没改。

将此处改为宋体就好。
创建蛇,用链表实现

当我们要实现这样一个贪吃蛇时,我们先要考虑用什么数据结构来实现,在这我们使用链表来搞。
可以看到我们蛇是一个一个节点连出来的。所以我们也将蛇的节点封装起来。
封装节点

那在节点中我们存储什么东西呢?在我们上述的终端中我们是可以用坐标把每一个地方表示出来的。所以我们就在节点中存储每一个节点的坐标和下一个节点的地点。因此代码实现就如下
  1. //蛇的节点、坐标,指针
  2. typedef struct SnakeNode
  3. {
  4.         int x;
  5.         int y;//坐标信息
  6.         struct SnakeNode* next;//下一个节点
  7. }SnakeNode;
  8. typedef SnakeNode* pSnakeNode;
复制代码
封装蛇

那我们要实现一个蛇,我们就要考虑内里要包罗哪些成员。起首我们肯定要有1.找到蛇身的蛇头指针,2.一个蛇活动的方向也需要,3.蛇每移动一下的状态也会有差别,4.从最后的原型图可以看出我们另有总分,5.一个食品的分,7,食品的分又是根据速度来的,速度我们就用当前代码休眠时间来表示,休眠时间约大速度越慢,8.食品我们也储存在内里。
蛇的方向和蛇的状态有很多种,我们就用enum罗列出来。
  1. //方向上下左右
  2. enum DIRECTION
  3. {
  4.         UP = 1,
  5.         DOWN,
  6.         LEFT,
  7.         RIGHT
  8. };
  9. //蛇的状态,正常,撞墙死,撞自己死,正常退出
  10. enum GAME_STATUS
  11. {
  12.         NORMAL,
  13.         KILL_BY_WALL,
  14.         KILL_BY_SELF,
  15.         EXIT_NORMAL
  16. };
  17. //贪吃蛇对象
  18. typedef struct Snake
  19. {
  20.         pSnakeNode psnake;//蛇头
  21.         pSnakeNode pfood;//食物
  22.         enum DIRECTION direction;//蛇的方向
  23.         enum GAME_STATUS status;//蛇的状态
  24.         int food_wight;//一个食物分数
  25.         int sorce;//总分数
  26.         int sleep_time;//休息时间
  27. }Snake;
  28. typedef Snake* pSnake;
复制代码
游戏初始化

初始化游戏函数
  1. //初始化游戏
  2. void GameStart(pSnake ps);
复制代码
在这个函数中我们需要将1.控制台界面巨细安排好,2.光标隐藏起来,3. 打印情况界面和功能先容,4. 绘制地图,5. 创建蛇,6. 创建食品。
对界面的操纵详见我上一篇关于Win32API的文章
Win32API的文章
具体实现如下:
  1. void GameStart(pSnake ps)
  2. {
  3.         //1.修改界面大小
  4.         system("mode con cols=150 lines=30");
  5.         system("title 贪吃蛇");
  6.         //2.隐藏光标
  7.         HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);
  8.         CONSOLE_CURSOR_INFO CursorInfo ;
  9.         GetConsoleCursorInfo(hOutPut, &CursorInfo);//获取控制台光标信息
  10.         CursorInfo.bVisible = false;
  11.         SetConsoleCursorInfo(hOutPut, &CursorInfo);//隐藏控制台光标信息
  12.        
  13.         //3. 打印环境界面和功能介绍
  14.         WelcomeToGame();
  15.         //4. 绘制地图
  16.         CreateMap();
  17.         //5. 创建蛇
  18.         IniteSnake(ps);
  19.         //6. 创建食物
  20.         IniteFood(ps);
  21. }
复制代码
光标设置函数

我们封装一个函数来设置光标坐标,以便后续使用。
  1. void SetPos(short x, short y)
  2. {
  3.         //获取一个句柄
  4.         HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);
  5.         //坐标
  6.         COORD pos = { x,y };
  7.         //设置光标坐标
  8.         SetConsoleCursorPosition(hOutPut, pos);
  9. }
复制代码
打印情况界面和功能先容函数

我们在这个函数中打印欢迎界面和游戏玩法。
  1. void WelcomeToGame()
  2. {
  3.         SetPos(40, 14);
  4.         wprintf(L"欢迎来到贪吃蛇小游戏\n");
  5.         SetPos(42, 20);
  6.         system("pause");
  7.         system("cls");
  8.         SetPos(25, 14);
  9.         wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");
  10.         SetPos(25, 15);
  11.         wprintf(L"加速能够得到更高的分数\n");
  12.         SetPos(42, 20);
  13.         system("pause");
  14.         system("cls");
  15. }
复制代码
绘制地图函数

我们绘制一个80行27列的地图。我们先将上下两行界限绘制出来,在绘制左右两个界限,注意左右时我们要从1到25最前面的已经绘制好了。另有每次绘制的实在光标位置肯定要盘算好根据本身设置的地图巨细。
  1. void CreateMap()
  2. {
  3.         SetPos(0, 0);
  4.         int i = 0;
  5.         for (i = 0; i < 80; i++)
  6.         {
  7.                 wprintf(L"%lc", WALL);
  8.         }
  9.         //下
  10.         SetPos(0, 26);
  11.         for (i = 0; i < 80; i++)
  12.         {
  13.                 wprintf(L"%lc", WALL);
  14.         }
  15.         for ( i = 1; i <= 25; i++)
  16.         {
  17.                 SetPos(0, i);
  18.                 wprintf(L"%lc", WALL);
  19.         }
  20.         //右
  21.         for ( i = 1; i <= 25; i++)
  22.         {
  23.                 SetPos(79, i);
  24.                 wprintf(L"%lc", WALL);
  25.         }
  26.         system("pause");
  27. }
复制代码
创建蛇

在这个函数中我们初始蛇有5个节点,用malloc申请空间,然后用头插法将节点接洽起来,然后打印。在将蛇的状态等成员设置。在创建蛇时因为我是字符只占一个空间,我就随便可以创建,但是有占两个时要在设置x坐标是下一个是加2。
  1. void IniteSnake(pSnake ps)
  2. {
  3.         pSnakeNode node = NULL;
  4.         //初始蛇身有5个节点
  5.         for (int i = 0; i < 5; i++)
  6.         {
  7.                 node = (pSnakeNode)malloc(sizeof(SnakeNode));
  8.                 if (node == NULL)
  9.                 {
  10.                         perror("IniteSnake malloc");
  11.                         exit(1);
  12.                 }
  13.                 //设置坐标
  14.                 node->x = POS_X + i;
  15.                 node->y = POS_Y;
  16.                 node->next = NULL;
  17.                 //头插
  18.                 if (ps->psnake == NULL)
  19.                         ps->psnake = node;
  20.                 else
  21.                 {
  22.                         node->next = ps->psnake;
  23.                         ps->psnake = node;
  24.                 }
  25.         }
  26.         //打印蛇身
  27.         node = ps->psnake;
  28.        
  29.         while (node)
  30.         {
  31.                 SetPos(node->x, node->y);
  32.                 wprintf(L"%c",BODY);
  33.                 node = node->next;
  34.         }
  35.         //设置蛇状态
  36.         ps->direction = RIGHT;
  37.         ps->sleep_time = 300;
  38.         ps->status = NORMAL;
  39.         ps->sorce = 0;
  40.         ps->food_wight = 30;
  41. }
复制代码
创建食品

我们创建一个食品节点,通过随机数生成坐标,但是要该坐标不能是墙,不能是蛇身。最后打印出来。在创建食品时因为我是字符只占一个空间,我就不用考虑蛇是否可以吃到食品,但是有占两个时要在设置食品x坐标要和蛇节点吻合,可以让蛇蛇吃到。
  1. void IniteFood(pSnake ps)
  2. {
  3.         pSnakeNode food = (pSnakeNode)malloc(sizeof(SnakeNode));
  4.         if (food == NULL)
  5.         {
  6.                 perror("IniteFood malloc");
  7.                 exit(1);
  8.         }
  9.         //随机生成食物坐标,判断与蛇是否重合
  10.         int x = 0;
  11.         int y = 0;
  12. again:
  13.         x = rand() % 78 + 1;
  14.         y = rand() % 23 + 1;
  15.                 pSnakeNode cur = ps->psnake;
  16.                 while (cur)
  17.                 {
  18.                         if (x == cur->x && y == cur->y)
  19.                         {
  20.                                 goto again;
  21.                         }
  22.                         cur = cur->next;
  23.                 }
  24.         food->x = x;
  25.         food->y = y;
  26.         food->next = NULL;
  27.         ps->pfood = food;
  28.         //打印食物
  29.         SetPos(food->x, food->y);
  30.         wprintf(L"%c", FOOD);
  31. }
复制代码
游戏运行

  1. void GameRun(pSnake ps)
  2. {
  3.         do {
  4.                 SetPos(90, 10);
  5.                 //右侧打印帮助信息
  6.                 PrintInfo(ps);
  7.                 //获取键盘信息
  8.                 //移动方向
  9.                 if (KEY_PRESS(VK_UP) && ps->direction != DOWN)
  10.                         ps->direction = UP;
  11.                 else if (KEY_PRESS(VK_DOWN) && ps->direction != UP)
  12.                         ps->direction = DOWN;
  13.                 else if (KEY_PRESS(VK_RIGHT) && ps->direction != LEFT)
  14.                         ps->direction = RIGHT;
  15.                 else if (KEY_PRESS(VK_LEFT) && ps->direction != RIGHT)
  16.                         ps->direction = LEFT;
  17.                 //加减速
  18.                 else if (KEY_PRESS(VK_F3))
  19.                 {
  20.                         if (ps->food_wight <= 50 && ps->food_wight >= 10)
  21.                         {
  22.                                 ps->sleep_time -= 10;
  23.                                 ps->food_wight += 2;
  24.                         }
  25.                 }
  26.                 else if (KEY_PRESS(VK_F4))
  27.                 {
  28.                         if (ps->food_wight <= 50 && ps->food_wight >= 10)
  29.                         {
  30.                                 ps->sleep_time += 10;
  31.                                 ps->food_wight -= 2;
  32.                         }
  33.                 }
  34.                 //暂停
  35.                 else if (KEY_PRESS(VK_SPACE))
  36.                         pause();
  37.                 //退出
  38.                 else if (KEY_PRESS(VK_ESCAPE))
  39.                 {
  40.                         ps->status = EXIT_NORMAL;
  41.                         break;
  42.                 }
  43.                 //判断分数超出限制调回
  44.                 if (ps->food_wight > 50)
  45.                 {
  46.                         ps->food_wight = 50;
  47.                 }
  48.                 else if (ps->food_wight < 10)
  49.                 {
  50.                         ps->food_wight = 10;
  51.                 }
  52.                 //蛇移动
  53.                 Sleep(ps->sleep_time);
  54.                 SnakeMove(ps);
  55.         } while (ps->status == NORMAL);
  56. }
复制代码
打印帮助信息函数

我们在游戏界面右边打印帮助信息。打印完帮助信息后我们在通过获取键盘信息来判断下一步应该怎么做。
  1. void PrintInfo(pSnake ps)
  2. {
  3.         printf("当前总分:%d", ps->sorce);
  4.         SetPos(90, 11);
  5.         printf("当前一个食物分数: %2d", ps->food_wight);
  6.         SetPos(90, 12);
  7.         printf("不能穿墙,不能咬到自己");
  8.         SetPos(90, 13);
  9.         printf("空格键暂停,esc键退出");
  10.         SetPos(90, 14);
  11.         printf("用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速");
  12.         SetPos(90, 15);
  13.         printf("加速减速最多10次,加速一次食物分数加2,减速一次食物分数减2");
  14. }
复制代码
停息函数

当我们接收键盘信息为空格停息时,我们调用该函数,该函数本质就是死循环睡眠。再次接收到空格时我们就恢复。
  1. void pause()
  2. {
  3.         while (1)
  4.         {
  5.                 Sleep(300);
  6.                 if (KEY_PRESS(VK_SPACE))
  7.                         break;
  8.         }
  9. }
复制代码
蛇移动函数

我们根据蛇移动方向来判断下一步在哪,实在就是将下一个位置处创建结点当头结点。但是我们需要判断移动后头结点位置是食品,照旧墙,照旧正常位置。然后看是否需要释放最后一个节点。
  1. void SnakeMove(pSnake ps)
  2. {
  3.         //创建一个节点
  4.         pSnakeNode node = (pSnakeNode)malloc(sizeof(SnakeNode));
  5.         if (node == NULL)
  6.         {
  7.                 perror("SnakeMove malloc");
  8.                 exit(1);
  9.         }
  10.         node->next = NULL;
  11.         //通过switch case来将下一个节点坐标赋值
  12.         switch (ps->direction)
  13.         {
  14.         case UP:
  15.                 node->x = ps->psnake->x;
  16.                 node->y = ps->psnake->y - 1;
  17.                 break;
  18.         case DOWN:
  19.                 node->x = ps->psnake->x;
  20.                 node->y = ps->psnake->y + 1;
  21.                 break;
  22.         case RIGHT:
  23.                 node->x = ps->psnake->x + 1;
  24.                 node->y = ps->psnake->y;
  25.                 break;
  26.         case LEFT:
  27.                 node->x = ps->psnake->x - 1;
  28.                 node->y = ps->psnake->y;
  29.                 break;
  30.         }
  31.         pSnakeNode tempNode = node;
  32.         //下一个节点是食物
  33.         if (node->x == ps->pfood->x && node->y == ps->pfood->y)
  34.         {
  35.                 EatFood(ps, node);
  36.         }
  37.         //不是食物
  38.         else
  39.         {
  40.                 NoFood(ps,node);
  41.         }
  42.         //判断移动后是否死来
  43.         if (NextIsSelf (ps,tempNode)== 1)
  44.         {
  45.                 ps->status = KILL_BY_SELF;
  46.         }
  47.         else if (tempNode->x == 0
  48.                 || tempNode->x == 79
  49.                 || tempNode->y == 0
  50.                 || tempNode->y == 27)
  51.         {
  52.                 ps->status = KILL_BY_WALL;
  53.         }
  54. }
复制代码
下一个是食品

当下个是食品我们就不用对最后一个节点释放。吃掉之后释放掉在创建下一个食品。
  1. void EatFood(pSnake ps,pSnakeNode node)
  2. {
  3.         //头插
  4.         node->next = ps->psnake;
  5.         ps->psnake = node;
  6.         //打印蛇
  7.         pSnakeNode cur = ps->psnake;
  8.         ps->sorce += ps->food_wight;
  9.         while (cur)
  10.         {
  11.                 SetPos(cur->x, cur->y);
  12.                 wprintf(L"%c", BODY);
  13.                 cur = cur->next;
  14.         }
  15.         //释放食物
  16.         free(ps->pfood);
  17.         IniteFood(ps);
  18. }
复制代码
下一个不是食品

下一个不是食品蛇往下一步走后需要释放掉最后一个节点。
  1. void NoFood(pSnake ps, pSnakeNode node)
  2. {
  3.         //头插
  4.         node->next = ps->psnake;
  5.         ps->psnake = node;
  6.         //打印蛇
  7.         pSnakeNode cur = ps->psnake;
  8.         while (cur)
  9.         {
  10.                 SetPos(cur->x, cur->y);
  11.                 wprintf(L"%c", BODY);
  12.                 cur = cur->next;
  13.         }
  14.         cur = ps->psnake;
  15.         while (cur->next->next)
  16.         {
  17.                 cur = cur->next;
  18.         }
  19.         pSnakeNode temp = cur->next;
  20.         SetPos(temp->x, temp->y);
  21.         printf(" ");
  22.         cur->next = NULL;
  23.         free(temp);
  24. }
复制代码
游戏结束

在游戏结束后通过蛇状态来打印死因,然后释放掉所有空间。
  1. void GameOver(pSnake ps)
  2. {
  3.         SetPos(40, 15);
  4.         if (ps->status == KILL_BY_SELF)
  5.                 printf("你撞到自己死了");
  6.         else if (ps->status == KILL_BY_WALL)
  7.                 printf("你撞到墙死了");
  8.         else if (ps->status == EXIT_NORMAL)
  9.                 printf("你正常退出了");
  10.         pSnakeNode cur = ps->psnake;
  11.         while (cur)
  12.         {
  13.                 ps->psnake = cur->next;
  14.                 free(cur);
  15.                 cur = ps->psnake;
  16.         }
  17.         free(ps->pfood);
  18. }
复制代码
源码

snake.h
  1. #pragma once#include <windows.h>#include <stdbool.h>#include <stdlib.h>#include <stdio.h>#include<locale.h>#include<time.h>#define WALL L'█'#define POS_X 25#define POS_Y 5#define BODY L'○'#define FOOD L'♥'#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&1)?1:0)//方向上下左右enum DIRECTION{        UP = 1,        DOWN,        LEFT,        RIGHT};//蛇的状态,正常,撞墙死,撞本身死,正常退出enum GAME_STATUS{        NORMAL,        KILL_BY_WALL,        KILL_BY_SELF,        EXIT_NORMAL};//蛇的节点、坐标,指针
  2. typedef struct SnakeNode
  3. {
  4.         int x;
  5.         int y;//坐标信息
  6.         struct SnakeNode* next;//下一个节点
  7. }SnakeNode;
  8. typedef SnakeNode* pSnakeNode;
  9. //贪吃蛇对象typedef struct Snake{        pSnakeNode psnake;//蛇头        pSnakeNode pfood;//食品        enum DIRECTION direction;//蛇的方向        enum GAME_STATUS status;//蛇的状态        int food_wight;//一个食品分数        int sorce;//总分数        int sleep_time;//苏息时间}Snake;typedef Snake* pSnake;//设置光标坐标void SetPos(short x, short y);//初始化游戏
  10. void GameStart(pSnake ps);
  11. //打印欢迎界面void WelcomeToGame();//绘制地图x 80, y 27void CreateMap();//5. 创建蛇void IniteSnake(pSnake ps);//6. 创建食品void IniteFood(pSnake ps);//游戏进行页面void GameRun(pSnake ps);//不是食品void NoFood(pSnake ps, pSnakeNode node);//吃食品void EatFood(pSnake ps, pSnakeNode node);//蛇移动void SnakeMove(pSnake ps);//游戏结束void GameOver(pSnake ps);
复制代码
snake.c
  1. # define _CRT_SECURE_NO_WARNINGS 1;#include"snake.h"//设置光标坐标void SetPos(short x, short y)
  2. {
  3.         //获取一个句柄
  4.         HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);
  5.         //坐标
  6.         COORD pos = { x,y };
  7.         //设置光标坐标
  8.         SetConsoleCursorPosition(hOutPut, pos);
  9. }
  10. //3. 打印情况界面和功能先容void WelcomeToGame()
  11. {
  12.         SetPos(40, 14);
  13.         wprintf(L"欢迎来到贪吃蛇小游戏\n");
  14.         SetPos(42, 20);
  15.         system("pause");
  16.         system("cls");
  17.         SetPos(25, 14);
  18.         wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");
  19.         SetPos(25, 15);
  20.         wprintf(L"加速能够得到更高的分数\n");
  21.         SetPos(42, 20);
  22.         system("pause");
  23.         system("cls");
  24. }
  25. //4. 绘制地图void CreateMap()
  26. {
  27.         SetPos(0, 0);
  28.         int i = 0;
  29.         for (i = 0; i < 80; i++)
  30.         {
  31.                 wprintf(L"%lc", WALL);
  32.         }
  33.         //下
  34.         SetPos(0, 26);
  35.         for (i = 0; i < 80; i++)
  36.         {
  37.                 wprintf(L"%lc", WALL);
  38.         }
  39.         for ( i = 1; i <= 25; i++)
  40.         {
  41.                 SetPos(0, i);
  42.                 wprintf(L"%lc", WALL);
  43.         }
  44.         //右
  45.         for ( i = 1; i <= 25; i++)
  46.         {
  47.                 SetPos(79, i);
  48.                 wprintf(L"%lc", WALL);
  49.         }
  50.         system("pause");
  51. }
  52. //5. 创建蛇void IniteSnake(pSnake ps)
  53. {
  54.         pSnakeNode node = NULL;
  55.         //初始蛇身有5个节点
  56.         for (int i = 0; i < 5; i++)
  57.         {
  58.                 node = (pSnakeNode)malloc(sizeof(SnakeNode));
  59.                 if (node == NULL)
  60.                 {
  61.                         perror("IniteSnake malloc");
  62.                         exit(1);
  63.                 }
  64.                 //设置坐标
  65.                 node->x = POS_X + i;
  66.                 node->y = POS_Y;
  67.                 node->next = NULL;
  68.                 //头插
  69.                 if (ps->psnake == NULL)
  70.                         ps->psnake = node;
  71.                 else
  72.                 {
  73.                         node->next = ps->psnake;
  74.                         ps->psnake = node;
  75.                 }
  76.         }
  77.         //打印蛇身
  78.         node = ps->psnake;
  79.        
  80.         while (node)
  81.         {
  82.                 SetPos(node->x, node->y);
  83.                 wprintf(L"%c",BODY);
  84.                 node = node->next;
  85.         }
  86.         //设置蛇状态
  87.         ps->direction = RIGHT;
  88.         ps->sleep_time = 300;
  89.         ps->status = NORMAL;
  90.         ps->sorce = 0;
  91.         ps->food_wight = 30;
  92. }
  93. //6. 创建食品void IniteFood(pSnake ps)
  94. {
  95.         pSnakeNode food = (pSnakeNode)malloc(sizeof(SnakeNode));
  96.         if (food == NULL)
  97.         {
  98.                 perror("IniteFood malloc");
  99.                 exit(1);
  100.         }
  101.         //随机生成食物坐标,判断与蛇是否重合
  102.         int x = 0;
  103.         int y = 0;
  104. again:
  105.         x = rand() % 78 + 1;
  106.         y = rand() % 23 + 1;
  107.                 pSnakeNode cur = ps->psnake;
  108.                 while (cur)
  109.                 {
  110.                         if (x == cur->x && y == cur->y)
  111.                         {
  112.                                 goto again;
  113.                         }
  114.                         cur = cur->next;
  115.                 }
  116.         food->x = x;
  117.         food->y = y;
  118.         food->next = NULL;
  119.         ps->pfood = food;
  120.         //打印食物
  121.         SetPos(food->x, food->y);
  122.         wprintf(L"%c", FOOD);
  123. }
  124. //初始化游戏void GameStart(pSnake ps)
  125. {
  126.         //1.修改界面大小
  127.         system("mode con cols=150 lines=30");
  128.         system("title 贪吃蛇");
  129.         //2.隐藏光标
  130.         HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);
  131.         CONSOLE_CURSOR_INFO CursorInfo ;
  132.         GetConsoleCursorInfo(hOutPut, &CursorInfo);//获取控制台光标信息
  133.         CursorInfo.bVisible = false;
  134.         SetConsoleCursorInfo(hOutPut, &CursorInfo);//隐藏控制台光标信息
  135.        
  136.         //3. 打印环境界面和功能介绍
  137.         WelcomeToGame();
  138.         //4. 绘制地图
  139.         CreateMap();
  140.         //5. 创建蛇
  141.         IniteSnake(ps);
  142.         //6. 创建食物
  143.         IniteFood(ps);
  144. }
  145. //打印帮助信息void PrintInfo(pSnake ps)
  146. {
  147.         printf("当前总分:%d", ps->sorce);
  148.         SetPos(90, 11);
  149.         printf("当前一个食物分数: %2d", ps->food_wight);
  150.         SetPos(90, 12);
  151.         printf("不能穿墙,不能咬到自己");
  152.         SetPos(90, 13);
  153.         printf("空格键暂停,esc键退出");
  154.         SetPos(90, 14);
  155.         printf("用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速");
  156.         SetPos(90, 15);
  157.         printf("加速减速最多10次,加速一次食物分数加2,减速一次食物分数减2");
  158. }
  159. //停息void pause()
  160. {
  161.         while (1)
  162.         {
  163.                 Sleep(300);
  164.                 if (KEY_PRESS(VK_SPACE))
  165.                         break;
  166.         }
  167. }
  168. //判断下一个是不是本身int NextIsSelf(pSnake ps, pSnakeNode node){        pSnakeNode cur = ps->psnake->next;        while (cur)        {                if (cur->x == node->x && cur->y == node->y)                        return 1;                cur = cur->next;        }        return 0;}//吃食品void EatFood(pSnake ps,pSnakeNode node)
  169. {
  170.         //头插
  171.         node->next = ps->psnake;
  172.         ps->psnake = node;
  173.         //打印蛇
  174.         pSnakeNode cur = ps->psnake;
  175.         ps->sorce += ps->food_wight;
  176.         while (cur)
  177.         {
  178.                 SetPos(cur->x, cur->y);
  179.                 wprintf(L"%c", BODY);
  180.                 cur = cur->next;
  181.         }
  182.         //释放食物
  183.         free(ps->pfood);
  184.         IniteFood(ps);
  185. }
  186. //不是食品void NoFood(pSnake ps, pSnakeNode node)
  187. {
  188.         //头插
  189.         node->next = ps->psnake;
  190.         ps->psnake = node;
  191.         //打印蛇
  192.         pSnakeNode cur = ps->psnake;
  193.         while (cur)
  194.         {
  195.                 SetPos(cur->x, cur->y);
  196.                 wprintf(L"%c", BODY);
  197.                 cur = cur->next;
  198.         }
  199.         cur = ps->psnake;
  200.         while (cur->next->next)
  201.         {
  202.                 cur = cur->next;
  203.         }
  204.         pSnakeNode temp = cur->next;
  205.         SetPos(temp->x, temp->y);
  206.         printf(" ");
  207.         cur->next = NULL;
  208.         free(temp);
  209. }
  210. //蛇移动void SnakeMove(pSnake ps)
  211. {
  212.         //创建一个节点
  213.         pSnakeNode node = (pSnakeNode)malloc(sizeof(SnakeNode));
  214.         if (node == NULL)
  215.         {
  216.                 perror("SnakeMove malloc");
  217.                 exit(1);
  218.         }
  219.         node->next = NULL;
  220.         //通过switch case来将下一个节点坐标赋值
  221.         switch (ps->direction)
  222.         {
  223.         case UP:
  224.                 node->x = ps->psnake->x;
  225.                 node->y = ps->psnake->y - 1;
  226.                 break;
  227.         case DOWN:
  228.                 node->x = ps->psnake->x;
  229.                 node->y = ps->psnake->y + 1;
  230.                 break;
  231.         case RIGHT:
  232.                 node->x = ps->psnake->x + 1;
  233.                 node->y = ps->psnake->y;
  234.                 break;
  235.         case LEFT:
  236.                 node->x = ps->psnake->x - 1;
  237.                 node->y = ps->psnake->y;
  238.                 break;
  239.         }
  240.         pSnakeNode tempNode = node;
  241.         //下一个节点是食物
  242.         if (node->x == ps->pfood->x && node->y == ps->pfood->y)
  243.         {
  244.                 EatFood(ps, node);
  245.         }
  246.         //不是食物
  247.         else
  248.         {
  249.                 NoFood(ps,node);
  250.         }
  251.         //判断移动后是否死来
  252.         if (NextIsSelf (ps,tempNode)== 1)
  253.         {
  254.                 ps->status = KILL_BY_SELF;
  255.         }
  256.         else if (tempNode->x == 0
  257.                 || tempNode->x == 79
  258.                 || tempNode->y == 0
  259.                 || tempNode->y == 27)
  260.         {
  261.                 ps->status = KILL_BY_WALL;
  262.         }
  263. }
  264. //游戏进行页面void GameRun(pSnake ps)
  265. {
  266.         do {
  267.                 SetPos(90, 10);
  268.                 //右侧打印帮助信息
  269.                 PrintInfo(ps);
  270.                 //获取键盘信息
  271.                 //移动方向
  272.                 if (KEY_PRESS(VK_UP) && ps->direction != DOWN)
  273.                         ps->direction = UP;
  274.                 else if (KEY_PRESS(VK_DOWN) && ps->direction != UP)
  275.                         ps->direction = DOWN;
  276.                 else if (KEY_PRESS(VK_RIGHT) && ps->direction != LEFT)
  277.                         ps->direction = RIGHT;
  278.                 else if (KEY_PRESS(VK_LEFT) && ps->direction != RIGHT)
  279.                         ps->direction = LEFT;
  280.                 //加减速
  281.                 else if (KEY_PRESS(VK_F3))
  282.                 {
  283.                         if (ps->food_wight <= 50 && ps->food_wight >= 10)
  284.                         {
  285.                                 ps->sleep_time -= 10;
  286.                                 ps->food_wight += 2;
  287.                         }
  288.                 }
  289.                 else if (KEY_PRESS(VK_F4))
  290.                 {
  291.                         if (ps->food_wight <= 50 && ps->food_wight >= 10)
  292.                         {
  293.                                 ps->sleep_time += 10;
  294.                                 ps->food_wight -= 2;
  295.                         }
  296.                 }
  297.                 //暂停
  298.                 else if (KEY_PRESS(VK_SPACE))
  299.                         pause();
  300.                 //退出
  301.                 else if (KEY_PRESS(VK_ESCAPE))
  302.                 {
  303.                         ps->status = EXIT_NORMAL;
  304.                         break;
  305.                 }
  306.                 //判断分数超出限制调回
  307.                 if (ps->food_wight > 50)
  308.                 {
  309.                         ps->food_wight = 50;
  310.                 }
  311.                 else if (ps->food_wight < 10)
  312.                 {
  313.                         ps->food_wight = 10;
  314.                 }
  315.                 //蛇移动
  316.                 Sleep(ps->sleep_time);
  317.                 SnakeMove(ps);
  318.         } while (ps->status == NORMAL);
  319. }
  320. //游戏结束void GameOver(pSnake ps)
  321. {
  322.         SetPos(40, 15);
  323.         if (ps->status == KILL_BY_SELF)
  324.                 printf("你撞到自己死了");
  325.         else if (ps->status == KILL_BY_WALL)
  326.                 printf("你撞到墙死了");
  327.         else if (ps->status == EXIT_NORMAL)
  328.                 printf("你正常退出了");
  329.         pSnakeNode cur = ps->psnake;
  330.         while (cur)
  331.         {
  332.                 ps->psnake = cur->next;
  333.                 free(cur);
  334.                 cur = ps->psnake;
  335.         }
  336.         free(ps->pfood);
  337. }
复制代码
test.c
  1. # define _CRT_SECURE_NO_WARNINGS 1;
  2. #include"snake.h"
  3. void test()
  4. {
  5.         int n = 4;
  6.         srand((unsigned int)time(NULL));
  7.         do {
  8.                 //创建贪吃蛇
  9.                 Snake snake = { 0 };
  10.                 //初始化游戏
  11.                 GameStart(&snake);
  12.                 //运行游戏
  13.                 GameRun(&snake);
  14.                 //结束游戏-善后工作
  15.                 GameOver(&snake);
  16.                 SetPos(10, 10);
  17.                 //system("cls");
  18.                 printf("是否再来一局Y/N: ");
  19.                 n = getchar();
  20.                 while (getchar() != '\n');
  21.                 system("cls");
  22.         } while (n == 'Y' || n == 'y');
  23.         SetPos(0, 29);
  24. }
  25. int main()
  26. {
  27.         //调节为本地状态
  28.         setlocale(LC_ALL, "");
  29.         test();
  30.         return 0;
  31. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

圆咕噜咕噜

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表