当前位置:   article > 正文

C语言——贪吃蛇_c语言贪吃蛇小游戏

c语言贪吃蛇小游戏

一. 游戏效果



贪吃蛇穿墙版


二. 游戏背景

贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。
贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》,后移植到各种平台上。具体如下:
起源。1977年,投币式墙壁游戏生产商Gremlin推出了经典的街机游戏《Blockade》,两名玩家要分别控制角色移动,角色会不停长大,而且走过的地方会变成围栏,谁先碰到围栏或碰到自己的身体就算输。
贪吃蛇最初的版本是像素版本,后来又衍生出3D版本、多人对战版本等2 3。
 

三、游戏开发日志

四、知识准备 

本次实现贪吃蛇会使⽤到的⼀些Win32 API知识,那么就学习⼀下

4.1 Win32 API

Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外, 它同时也是⼀个很⼤的服务中⼼,调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程式达到开启 视窗、描绘图形、使⽤周边设备等⽬的,由于这些函数服务的对象是应⽤程序(Application), 所以便 称之为 Application Programming Interface, 简称 API 函数。 WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。

4.2 控制台程序

平常我们运⾏起来的⿊框程序其实就是控制台程序。
我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽,也可以通过命令设置控制台窗⼝的名字:
设置控制台窗⼝的⼤⼩,30⾏,100列,设置控制台窗⼝的名字。
  1. //控制台窗口设置
  2. system("mode con cols=100 lines=35");
  3. system("title 贪吃蛇");

4.3  控制台屏幕上的坐标COORD

COORD 是Windows API中定义的⼀种结构,表⽰⼀个字符在控制台屏幕上的坐标

  1. typedef struct _COORD {
  2. SHORT X;
  3. SHORT Y;
  4. } COORD, *PCOORD;

4.4  GetStdHandle

GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
 
  1. HANDLE hOutput = NULL;
  2. //获取标准输出的句柄(⽤来标识不同设备的数值)
  3. hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

4.5 GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息
 
  1. HANDLE hOutput = NULL;
  2. //获取标准输出的句柄(⽤来标识不同设备的数值)
  3. hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  4. CONSOLE_CURSOR_INFO CursorInfo;
  5. GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

4.5.1  CONSOLE_CURSOR_INFO

这个结构体,包含有关控制台游标的信息
  1. typedef struct _CONSOLE_CURSOR_INFO {
  2. DWORD dwSize;
  3. BOOL bVisible;
  4. } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
(1) dwSize,由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条。
(2)  bVisible,游标的可⻅性。 如果光标可⻅,则此成员为 TRUE。
CursorInfo.bVisible = false; //隐藏控制台光标

5.6  SetConsoleCursorInfo

设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。

  1. HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  2. //影藏光标操作
  3. CONSOLE_CURSOR_INFO CursorInfo;
  4. GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
  5. CursorInfo.bVisible = false; //隐藏控制台光标
  6. SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

5.7  SetConsoleCursorPosition

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

  1. COORD pos = { 10, 5};
  2. HANDLE hOutput = NULL;
  3. //获取标准输出的句柄(⽤来标识不同设备的数值)
  4. hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  5. //设置标准输出上光标的位置为pos
  6. SetConsoleCursorPosition(hOutput, pos);
温馨提示:

这里我们可以将SetPos:封装⼀个设置光标位置的函数

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

5.8 GetAsyncKeyState

获取按键情况,将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果 返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.
我们这里定义一个宏:
 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

5.9 宽字符打印

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

5.9.1  setlocale函数

char* setlocale (int category, const char* locale);

setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。 setlocale 的第⼀个参数如果是LC_ALL,就会影响所有的类项。

C标准给第⼆个参数仅定义了2种可能取值:"C"和"  "。
在任意程序执⾏开始,都会隐藏式执⾏调⽤:
 setlocale(LC_ALL, "C");

当地区设置为"C"时,库函数按正常⽅式执⾏.

当地区设置为"  "时,这种模式下程序会适应本地环境。⽐如:切换到我们的本地模式后就⽀
持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境

宽字符的打印如下:

  1. #include <stdio.h>
  2. #include<locale.h>
  3. int main() {
  4. setlocale(LC_ALL, "");
  5. wchar_t ch1 = L'●';
  6. wprintf(L"%c\n", ch1);
  7. return 0;
  8. }

五、游戏实现

5.1 游戏逻辑主体

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include"snake.h"
  3. #include<locale.h>
  4. #include<stdio.h>
  5. int main()
  6. {
  7. char ch;
  8. setlocale(LC_ALL, "");//切换到本地环境,支持宽字符
  9. srand((unsigned int)time(NULL));
  10. do
  11. {
  12. Snake snake = { 0 };
  13. GameInit(&snake);
  14. GameRun(&snake);
  15. GameOver(&snake);
  16. printf("小垃圾还要再来吗?是:Y,否:N\n");
  17. ch = getchar();
  18. getchar();
  19. } while (ch == 'y' || ch == 'Y');
  20. return 0;
  21. }

5.2  游戏初始化实现

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include"snake.h"
  3. #define WALL L'□'
  4. #define BODY L'●'
  5. #define FOOD L'█'
  6. void SetPos(short x, short y)
  7. {
  8. COORD pos = { x, y };
  9. HANDLE hOutput = NULL;
  10. //获取标准输出的句柄(⽤来标识不同设备的数值)
  11. hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  12. //设置标准输出上光标的位置为pos
  13. SetConsoleCursorPosition(hOutput, pos);
  14. }
  15. void WelcomeToGame()
  16. {
  17. SetPos(40, 13);
  18. printf("欢迎来到贪吃蛇小游戏");
  19. SetPos(42, 22);
  20. system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
  21. system("cls");
  22. SetPos(25, 12);
  23. printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
  24. SetPos(42, 22);
  25. system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
  26. system("cls");
  27. /*getchar();*/
  28. }
  29. void CreateMap()
  30. {
  31. SetPos(0,0);
  32. int i = 0;
  33. for(i=0;i<58;i=i+2)
  34. {
  35. wprintf(L"%c", WALL);
  36. }
  37. SetPos(0, 26);
  38. for (i = 0; i < 58; i = i + 2)
  39. {
  40. wprintf(L"%c", WALL);
  41. }
  42. for (i = 1; i <26; i++)
  43. {
  44. SetPos(0, i);
  45. wprintf(L"%c", WALL);
  46. }
  47. for (i = 1; i < 26; i++)
  48. {
  49. SetPos(56, i);
  50. wprintf(L"%c", WALL);
  51. }
  52. /*getchar();*/
  53. }
  54. void InitSnake(Snake* snake)
  55. {
  56. //初始化蛇身
  57. for (int i = 0; i < 5; i++)
  58. {
  59. SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));
  60. node->x = 24 + 2 * i;
  61. node->y = 15;
  62. node->next = NULL;
  63. if (snake->pSnake== NULL)
  64. {
  65. snake->pSnake= node;
  66. }
  67. else
  68. {
  69. node->next = snake->pSnake;
  70. snake->pSnake = node;
  71. }
  72. }
  73. SnakeNode* cur = snake->pSnake;
  74. while (cur)
  75. {
  76. int x = cur->x;
  77. int y = cur->y;
  78. SetPos(x, y);
  79. wprintf(L"%c", BODY);
  80. cur = cur->next;
  81. }
  82. snake->status = RUN;
  83. snake->dir = RIGHT;
  84. snake->FoodWeight = 10;
  85. snake->pFood = NULL;
  86. snake->score = 0;
  87. snake->SleepTime = 200;
  88. }
  89. void CreateFood(Snake* snake)
  90. {
  91. int x = 0;
  92. int y = 0;
  93. again:
  94. do
  95. {
  96. x = rand() % 53 + 2;
  97. y = rand() % 24 + 1;
  98. } while (x % 2 != 0);
  99. SnakeNode* cur = snake->pSnake;
  100. do
  101. {
  102. if (x == cur->x && y == cur->y)
  103. {
  104. goto again;
  105. }
  106. cur = cur->next;
  107. } while (cur);
  108. SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));
  109. food->x = x;
  110. food->y = y;
  111. snake->pFood = food;
  112. SetPos(x, y);
  113. wprintf(L"%c", FOOD);
  114. /*getchar();*/
  115. }
  116. void GameInit(Snake* snake)
  117. {
  118. //控制台窗口设置
  119. system("mode con cols=100 lines=35");
  120. system("title 贪吃蛇");
  121. //隐藏光标
  122. HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  123. CONSOLE_CURSOR_INFO CursorInfo;
  124. GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
  125. CursorInfo.bVisible = false; //隐藏控制台光标
  126. SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
  127. //打印欢迎界面
  128. WelcomeToGame();
  129. //创建地图
  130. CreateMap();
  131. //初始化贪吃蛇
  132. InitSnake(snake);
  133. //创建食物
  134. CreateFood(snake);
  135. }

5.3 游戏运行实现

  1. void PrintHelpInfo()
  2. {
  3. SetPos(60, 13);
  4. printf("1. 不能穿墙不能咬到自己\n");
  5. SetPos(60, 14);
  6. printf("2.↑.↓.←.→分别控制蛇的移动\n");
  7. SetPos(60, 15);
  8. printf("3. F3为加速,F4为减速\n");
  9. SetPos(60, 16);
  10. printf("4. ESC-退出,空格-暂停\n");
  11. }
  12. void Pause()
  13. {
  14. while (1)
  15. {
  16. Sleep(200);
  17. if (KEY_PRESS(VK_SPACE) == 1)
  18. {
  19. break;
  20. }
  21. }
  22. }
  23. void EatFood(Snake* snake, SnakeNode* snakenext)
  24. {
  25. snakenext->next = snake->pSnake;
  26. snake->pSnake = snakenext;
  27. SnakeNode* cur = snake->pSnake;
  28. while (cur)
  29. {
  30. SetPos(cur->x, cur->y);
  31. wprintf(L"%lc", BODY);
  32. cur = cur->next;
  33. }
  34. free(snake->pFood);
  35. snake->pFood = NULL;
  36. CreateFood(snake);
  37. }
  38. void NoEatFood(Snake* snake, SnakeNode* snakenext)
  39. {
  40. snakenext->next = snake->pSnake;
  41. snake->pSnake = snakenext;
  42. SnakeNode* cur = snake->pSnake;
  43. while (cur->next->next)
  44. {
  45. SetPos(cur->x, cur->y);
  46. wprintf(L"%lc", BODY);
  47. cur = cur->next;
  48. }
  49. SetPos(cur->x, cur->y);
  50. wprintf(L"%lc", BODY);
  51. SetPos(cur->next->x, cur->next->y);
  52. printf(" ");
  53. free(cur->next);
  54. cur->next = NULL;
  55. }
  56. void SnakeMove(Snake* snake)
  57. {
  58. SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
  59. if (snake->dir == UP)
  60. {
  61. snakenext->x = snake->pSnake->x;
  62. snakenext->y = snake->pSnake->y -1;
  63. snakenext->next = NULL;
  64. }
  65. else if (snake->dir == DOWN)
  66. {
  67. snakenext->x = snake->pSnake->x;
  68. snakenext->y = snake->pSnake->y +1;
  69. snakenext->next = NULL;
  70. }
  71. if (snake->dir == LEFT)
  72. {
  73. snakenext->x = snake->pSnake->x-2;
  74. snakenext->y = snake->pSnake->y ;
  75. snakenext->next = NULL;
  76. }
  77. if (snake->dir == RIGHT)
  78. {
  79. snakenext->x = snake->pSnake->x + 2;
  80. snakenext->y = snake->pSnake->y;
  81. snakenext->next = NULL;
  82. }
  83. //判断下一个节点是否为食物
  84. if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
  85. {
  86. EatFood(snake,snakenext);//吃食物
  87. snake->score += snake->FoodWeight;
  88. }
  89. else
  90. {
  91. NoEatFood(snake,snakenext);//不吃食物
  92. }
  93. //碰撞检测
  94. if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26)
  95. {
  96. snake->status = KILL_BY_WALL;
  97. }
  98. SnakeNode* cur = snake->pSnake->next;
  99. while (cur)
  100. {
  101. if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
  102. {
  103. snake->status = KILL_BY_SELF;
  104. }
  105. cur = cur->next;
  106. }
  107. }
  108. void GameRun(Snake* snake)
  109. {
  110. //打印帮助信息
  111. PrintHelpInfo();
  112. do
  113. {
  114. SetPos(60, 8);
  115. printf("游戏总得分:%5d ", snake->score);
  116. SetPos(60, 9);
  117. printf("每个食物的分数:%2d ", snake->FoodWeight);
  118. if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN)
  119. {
  120. snake->dir = UP;
  121. }
  122. else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP)
  123. {
  124. snake->dir = DOWN;
  125. }
  126. else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT)
  127. {
  128. snake->dir = RIGHT;
  129. }
  130. else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT)
  131. {
  132. snake->dir =LEFT;
  133. }
  134. else if (KEY_PRESS(VK_F3) == 1)
  135. {
  136. if (snake->SleepTime>=80)
  137. {
  138. snake->SleepTime -= 30;
  139. snake->FoodWeight += 2;
  140. }
  141. }
  142. else if (KEY_PRESS(VK_F4) == 1)
  143. {
  144. if (snake->SleepTime<=320)
  145. {
  146. snake->SleepTime += 30;
  147. snake->FoodWeight -= 2;
  148. }
  149. }
  150. else if (KEY_PRESS(VK_ESCAPE) == 1)
  151. {
  152. snake->status = OVER;
  153. break;
  154. }
  155. else if (KEY_PRESS(VK_SPACE) == 1)
  156. {
  157. Pause();
  158. }
  159. SnakeMove(snake);
  160. Sleep(snake->SleepTime);//每一帧停0.2s
  161. } while (snake->status==RUN);
  162. }

5.4 游戏结束实现

  1. void GameOver(Snake* snake)
  2. {
  3. switch (snake->status)
  4. {
  5. case KILL_BY_WALL:
  6. SetPos(20, 15);
  7. printf("你已经撞墙了,小垃圾!\n");
  8. break;
  9. case KILL_BY_SELF:
  10. SetPos(20, 15);
  11. printf("你已经自杀了,小垃圾!\n");
  12. break;
  13. case OVER:
  14. SetPos(20, 15);
  15. printf("你退出游戏了,小垃圾!\n");
  16. break;
  17. }
  18. SetPos(0, 29);
  19. }

六、 完整代码

6.1 snake.h

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include<stdbool.h>
  3. #include<stdio.h>
  4. #include<windows.h>
  5. #include<stdlib.h>
  6. #include<time.h>
  7. #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
  8. enum direction{UP = 1, DOWN, LEFT, RIGHT};//蛇的方向
  9. enum game_status{RUN,KILL_BY_WALL,KILL_BY_SELF,OVER};
  10. typedef struct SnakeNode
  11. {
  12. int x;
  13. int y;
  14. struct SnakeNode* next;
  15. }SnakeNode;
  16. typedef struct Snake
  17. {
  18. SnakeNode* pSnake;//指向贪吃蛇头节点
  19. SnakeNode* pFood;//指向食物的节点
  20. int score;
  21. int FoodWeight;
  22. int SleepTime;
  23. enum direction dir;//蛇的方向
  24. enum game_status status;//游戏状态
  25. }Snake;
  26. void GameInit(Snake*snake);
  27. void WelcomeToGame();
  28. void CreateMap();
  29. void InitSnake(Snake* snake);
  30. void CreateFood(Snake* snake);
  31. void GameRun(Snake* snake);
  32. void PrintHelpInfo();
  33. void Pause();
  34. void SnakeMove(Snake* snake);
  35. void EatFood(Snake* snake,SnakeNode*snakenext);
  36. void NoEatFood(Snake* snake, SnakeNode* snakenext);
  37. void GameOver(Snake* snake);

6.2 snake.c

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include"snake.h"
  3. #define WALL L'□'
  4. #define BODY L'●'
  5. #define FOOD L'█'
  6. void SetPos(short x, short y)
  7. {
  8. COORD pos = { x, y };
  9. HANDLE hOutput = NULL;
  10. //获取标准输出的句柄(⽤来标识不同设备的数值)
  11. hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  12. //设置标准输出上光标的位置为pos
  13. SetConsoleCursorPosition(hOutput, pos);
  14. }
  15. void WelcomeToGame()
  16. {
  17. SetPos(40, 13);
  18. printf("欢迎来到贪吃蛇小游戏");
  19. SetPos(42, 22);
  20. system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
  21. system("cls");
  22. SetPos(25, 12);
  23. printf("↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
  24. SetPos(42, 22);
  25. system("pause");//会显示按任意键继续的信息,按任意键后继续执行下一步
  26. system("cls");
  27. /*getchar();*/
  28. }
  29. void CreateMap()
  30. {
  31. SetPos(0,0);
  32. int i = 0;
  33. for(i=0;i<58;i=i+2)
  34. {
  35. wprintf(L"%c", WALL);
  36. }
  37. SetPos(0, 26);
  38. for (i = 0; i < 58; i = i + 2)
  39. {
  40. wprintf(L"%c", WALL);
  41. }
  42. for (i = 1; i <26; i++)
  43. {
  44. SetPos(0, i);
  45. wprintf(L"%c", WALL);
  46. }
  47. for (i = 1; i < 26; i++)
  48. {
  49. SetPos(56, i);
  50. wprintf(L"%c", WALL);
  51. }
  52. /*getchar();*/
  53. }
  54. void InitSnake(Snake* snake)
  55. {
  56. //初始化蛇身
  57. for (int i = 0; i < 5; i++)
  58. {
  59. SnakeNode* node = (SnakeNode*)malloc(sizeof(SnakeNode));
  60. node->x = 24 + 2 * i;
  61. node->y = 15;
  62. node->next = NULL;
  63. if (snake->pSnake== NULL)
  64. {
  65. snake->pSnake= node;
  66. }
  67. else
  68. {
  69. node->next = snake->pSnake;
  70. snake->pSnake = node;
  71. }
  72. }
  73. SnakeNode* cur = snake->pSnake;
  74. while (cur)
  75. {
  76. int x = cur->x;
  77. int y = cur->y;
  78. SetPos(x, y);
  79. wprintf(L"%c", BODY);
  80. cur = cur->next;
  81. }
  82. snake->status = RUN;
  83. snake->dir = RIGHT;
  84. snake->FoodWeight = 10;
  85. snake->pFood = NULL;
  86. snake->score = 0;
  87. snake->SleepTime = 200;
  88. }
  89. void CreateFood(Snake* snake)
  90. {
  91. int x = 0;
  92. int y = 0;
  93. again:
  94. do
  95. {
  96. x = rand() % 53 + 2;
  97. y = rand() % 24 + 1;
  98. } while (x % 2 != 0);
  99. SnakeNode* cur = snake->pSnake;
  100. do
  101. {
  102. if (x == cur->x && y == cur->y)
  103. {
  104. goto again;
  105. }
  106. cur = cur->next;
  107. } while (cur);
  108. SnakeNode* food = (SnakeNode*)malloc(sizeof(SnakeNode));
  109. food->x = x;
  110. food->y = y;
  111. snake->pFood = food;
  112. SetPos(x, y);
  113. wprintf(L"%c", FOOD);
  114. /*getchar();*/
  115. }
  116. void GameInit(Snake* snake)
  117. {
  118. //控制台窗口设置
  119. system("mode con cols=100 lines=35");
  120. system("title 贪吃蛇");
  121. //隐藏光标
  122. HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  123. CONSOLE_CURSOR_INFO CursorInfo;
  124. GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
  125. CursorInfo.bVisible = false; //隐藏控制台光标
  126. SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
  127. //打印欢迎界面
  128. WelcomeToGame();
  129. //创建地图
  130. CreateMap();
  131. //初始化贪吃蛇
  132. InitSnake(snake);
  133. //创建食物
  134. CreateFood(snake);
  135. }
  136. void PrintHelpInfo()
  137. {
  138. SetPos(60, 13);
  139. printf("1. 不能穿墙不能咬到自己\n");
  140. SetPos(60, 14);
  141. printf("2.↑.↓.←.→分别控制蛇的移动\n");
  142. SetPos(60, 15);
  143. printf("3. F3为加速,F4为减速\n");
  144. SetPos(60, 16);
  145. printf("4. ESC-退出,空格-暂停\n");
  146. }
  147. void Pause()
  148. {
  149. while (1)
  150. {
  151. Sleep(200);
  152. if (KEY_PRESS(VK_SPACE) == 1)
  153. {
  154. break;
  155. }
  156. }
  157. }
  158. void EatFood(Snake* snake, SnakeNode* snakenext)
  159. {
  160. snakenext->next = snake->pSnake;
  161. snake->pSnake = snakenext;
  162. SnakeNode* cur = snake->pSnake;
  163. while (cur)
  164. {
  165. SetPos(cur->x, cur->y);
  166. wprintf(L"%lc", BODY);
  167. cur = cur->next;
  168. }
  169. free(snake->pFood);
  170. snake->pFood = NULL;
  171. CreateFood(snake);
  172. }
  173. void NoEatFood(Snake* snake, SnakeNode* snakenext)
  174. {
  175. snakenext->next = snake->pSnake;
  176. snake->pSnake = snakenext;
  177. SnakeNode* cur = snake->pSnake;
  178. while (cur->next->next)
  179. {
  180. SetPos(cur->x, cur->y);
  181. wprintf(L"%lc", BODY);
  182. cur = cur->next;
  183. }
  184. SetPos(cur->x, cur->y);
  185. wprintf(L"%lc", BODY);
  186. SetPos(cur->next->x, cur->next->y);
  187. printf(" ");
  188. free(cur->next);
  189. cur->next = NULL;
  190. }
  191. void SnakeMove(Snake* snake)
  192. {
  193. SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
  194. if (snake->dir == UP)
  195. {
  196. snakenext->x = snake->pSnake->x;
  197. snakenext->y = snake->pSnake->y -1;
  198. snakenext->next = NULL;
  199. }
  200. else if (snake->dir == DOWN)
  201. {
  202. snakenext->x = snake->pSnake->x;
  203. snakenext->y = snake->pSnake->y +1;
  204. snakenext->next = NULL;
  205. }
  206. if (snake->dir == LEFT)
  207. {
  208. snakenext->x = snake->pSnake->x-2;
  209. snakenext->y = snake->pSnake->y ;
  210. snakenext->next = NULL;
  211. }
  212. if (snake->dir == RIGHT)
  213. {
  214. snakenext->x = snake->pSnake->x + 2;
  215. snakenext->y = snake->pSnake->y;
  216. snakenext->next = NULL;
  217. }
  218. //判断下一个节点是否为食物
  219. if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
  220. {
  221. EatFood(snake,snakenext);//吃食物
  222. snake->score += snake->FoodWeight;
  223. }
  224. else
  225. {
  226. NoEatFood(snake,snakenext);//不吃食物
  227. }
  228. //碰撞检测
  229. if (snake->pSnake->x == 0 || snake->pSnake->x == 56 || snake->pSnake->y == 0 || snake->pSnake->y == 26)
  230. {
  231. snake->status = KILL_BY_WALL;
  232. }
  233. SnakeNode* cur = snake->pSnake->next;
  234. while (cur)
  235. {
  236. if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
  237. {
  238. snake->status = KILL_BY_SELF;
  239. }
  240. cur = cur->next;
  241. }
  242. }
  243. void GameRun(Snake* snake)
  244. {
  245. //打印帮助信息
  246. PrintHelpInfo();
  247. do
  248. {
  249. SetPos(60, 8);
  250. printf("游戏总得分:%5d ", snake->score);
  251. SetPos(60, 9);
  252. printf("每个食物的分数:%2d ", snake->FoodWeight);
  253. if (KEY_PRESS(VK_UP) == 1&&snake->dir!=DOWN)
  254. {
  255. snake->dir = UP;
  256. }
  257. else if (KEY_PRESS(VK_DOWN) == 1 && snake->dir != UP)
  258. {
  259. snake->dir = DOWN;
  260. }
  261. else if (KEY_PRESS(VK_RIGHT) == 1 && snake->dir != LEFT)
  262. {
  263. snake->dir = RIGHT;
  264. }
  265. else if (KEY_PRESS(VK_LEFT) == 1 && snake->dir != RIGHT)
  266. {
  267. snake->dir =LEFT;
  268. }
  269. else if (KEY_PRESS(VK_F3) == 1)
  270. {
  271. if (snake->SleepTime>=80)
  272. {
  273. snake->SleepTime -= 30;
  274. snake->FoodWeight += 2;
  275. }
  276. }
  277. else if (KEY_PRESS(VK_F4) == 1)
  278. {
  279. if (snake->SleepTime<=320)
  280. {
  281. snake->SleepTime += 30;
  282. snake->FoodWeight -= 2;
  283. }
  284. }
  285. else if (KEY_PRESS(VK_ESCAPE) == 1)
  286. {
  287. snake->status = OVER;
  288. break;
  289. }
  290. else if (KEY_PRESS(VK_SPACE) == 1)
  291. {
  292. Pause();
  293. }
  294. SnakeMove(snake);
  295. Sleep(snake->SleepTime);//每一帧停0.2s
  296. } while (snake->status==RUN);
  297. }
  298. void GameOver(Snake* snake)
  299. {
  300. switch (snake->status)
  301. {
  302. case KILL_BY_WALL:
  303. SetPos(20, 15);
  304. printf("你已经撞墙了,小垃圾!\n");
  305. break;
  306. case KILL_BY_SELF:
  307. SetPos(20, 15);
  308. printf("你已经自杀了,小垃圾!\n");
  309. break;
  310. case OVER:
  311. SetPos(20, 15);
  312. printf("你退出游戏了,小垃圾!\n");
  313. break;
  314. }
  315. SetPos(0, 29);
  316. }

6.3 text.c

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include"snake.h"
  3. #include<locale.h>
  4. #include<stdio.h>
  5. int main()
  6. {
  7. char ch;
  8. setlocale(LC_ALL, "");//切换到本地环境,支持宽字符
  9. srand((unsigned int)time(NULL));
  10. do
  11. {
  12. Snake snake = { 0 };
  13. GameInit(&snake);
  14. GameRun(&snake);
  15. GameOver(&snake);
  16. printf("小垃圾还要再来吗?是:Y,否:N\n");
  17. ch = getchar();
  18. getchar();
  19. } while (ch == 'y' || ch == 'Y');
  20. return 0;
  21. }

七、穿墙版(进阶版)

穿墙也非常简单,只是将撞墙检测去除,改为

1)判断snakenext->y ==0,则snakenext->y =25

2)判断snakenext->y ==26,则snakenext->y =1

3)判断snakenext->x==0,则snakenext->x =54

4)   判断snakenext->x==56,则snakenext->x =2

其余状态为正常吃食物状态

只在snake.c中的void SnakeMove(Snake* snake)中略有改动,其余不变

  1. void SnakeMove(Snake* snake)
  2. {
  3. SnakeNode* snakenext = (SnakeNode*)malloc(sizeof(SnakeNode));
  4. if (snake->dir == UP)
  5. {
  6. snakenext->x = snake->pSnake->x;
  7. snakenext->y = snake->pSnake->y -1;
  8. snakenext->next = NULL;
  9. }
  10. else if (snake->dir == DOWN)
  11. {
  12. snakenext->x = snake->pSnake->x;
  13. snakenext->y = snake->pSnake->y +1;
  14. snakenext->next = NULL;
  15. }
  16. if (snake->dir == LEFT)
  17. {
  18. snakenext->x = snake->pSnake->x-2;
  19. snakenext->y = snake->pSnake->y ;
  20. snakenext->next = NULL;
  21. }
  22. if (snake->dir == RIGHT)
  23. {
  24. snakenext->x = snake->pSnake->x + 2;
  25. snakenext->y = snake->pSnake->y;
  26. snakenext->next = NULL;
  27. }
  28. //判断下一个节点是否为食物
  29. if (snakenext->x == snake->pFood->x && snakenext->y == snake->pFood->y)
  30. {
  31. EatFood(snake,snakenext);//吃食物
  32. snake->score += snake->FoodWeight;
  33. }
  34. else
  35. {
  36. if (snakenext->y == 0)
  37. {
  38. snakenext->y = 25;
  39. snakenext->next = snake->pSnake;
  40. snake->pSnake = snakenext;
  41. SnakeNode* cur = snake->pSnake;
  42. while (cur->next->next)
  43. {
  44. SetPos(cur->x, cur->y);
  45. wprintf(L"%lc", BODY);
  46. cur = cur->next;
  47. }
  48. SetPos(cur->x, cur->y);
  49. wprintf(L"%lc", BODY);
  50. SetPos(cur->next->x, cur->next->y);
  51. printf(" ");
  52. free(cur->next);
  53. cur->next = NULL;
  54. }
  55. else if (snakenext->y == 26)
  56. {
  57. snakenext->y =1;
  58. snakenext->next = snake->pSnake;
  59. snake->pSnake = snakenext;
  60. SnakeNode* cur = snake->pSnake;
  61. while (cur->next->next)
  62. {
  63. SetPos(cur->x, cur->y);
  64. wprintf(L"%lc", BODY);
  65. cur = cur->next;
  66. }
  67. SetPos(cur->x, cur->y);
  68. wprintf(L"%lc", BODY);
  69. SetPos(cur->next->x, cur->next->y);
  70. printf(" ");
  71. free(cur->next);
  72. cur->next = NULL;
  73. }
  74. else if (snakenext->x == 0)
  75. {
  76. snakenext->x = 54;
  77. snakenext->next = snake->pSnake;
  78. snake->pSnake = snakenext;
  79. SnakeNode* cur = snake->pSnake;
  80. while (cur->next->next)
  81. {
  82. SetPos(cur->x, cur->y);
  83. wprintf(L"%lc", BODY);
  84. cur = cur->next;
  85. }
  86. SetPos(cur->x, cur->y);
  87. wprintf(L"%lc", BODY);
  88. SetPos(cur->next->x, cur->next->y);
  89. printf(" ");
  90. free(cur->next);
  91. cur->next = NULL;
  92. }
  93. else if (snakenext->x == 56)
  94. {
  95. snakenext->x =2;
  96. snakenext->next = snake->pSnake;
  97. snake->pSnake = snakenext;
  98. SnakeNode* cur = snake->pSnake;
  99. while (cur->next->next)
  100. {
  101. SetPos(cur->x, cur->y);
  102. wprintf(L"%lc", BODY);
  103. cur = cur->next;
  104. }
  105. SetPos(cur->x, cur->y);
  106. wprintf(L"%lc", BODY);
  107. SetPos(cur->next->x, cur->next->y);
  108. printf(" ");
  109. free(cur->next);
  110. cur->next = NULL;
  111. }
  112. else
  113. {
  114. NoEatFood(snake, snakenext);//不吃食物
  115. }
  116. }
  117. //穿墙检测
  118. SnakeNode* cur = snake->pSnake->next;
  119. while (cur)
  120. {
  121. if (cur->x == snake->pSnake->x && cur->y == snake->pSnake->y)
  122. {
  123. snake->status = KILL_BY_SELF;
  124. }
  125. cur = cur->next;
  126. }
  127. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/463447
推荐阅读
相关标签
  

闽ICP备14008679号