飞道的博客

C语言写个贪吃蛇游戏

209人阅读  评论(0)

贪吃蛇是个非常经典的游戏,用C语言来实现也是一个好玩的事情。这个游戏我写完后放在知乎,竟然点赞的人数超级多。我觉得大家喜欢,一个方面是因为写得简单,大家都能看得懂,一个可扩展性还是非常强的。

我试了说一下这个代码 核心的三个函数


   
  1. menu();
  2. setup();
  3. draw();

menu用来设置菜单,也就是我们一运行看到的那个。setup用来设置参数,我们需要设置高度和宽度,还有分数,食物的位置。draw也就是画,也就是画整个画面。

还有一个枚举类型 这个结构体用来设置蛇的几个状态,我觉得这个也是面向对象编程的一个思想,把蛇的状态都封装成一个枚举类型。


   
  1. typedef enum
  2. {
  3. STOP = 0,
  4. LEFT,
  5. RIGHT,
  6. UP,
  7. DOWN
  8. }Direction;

还有


   
  1. /*判断贪吃蛇的长度*/
  2. void logic()

这个函数,这个函数应该是整个贪吃蛇的精髓了,要理解代码怎么把蛇给连接起来。用了点巧妙的东西。

来看这里面的关键代码


   
  1. /*把上一个位置记下*/
  2. int lastX = tailX[ 0];
  3. int lastY = tailY[ 0];
  4. int last2X, last2Y;
  5. /*重新获取当前的位置*/
  6. tailX[ 0]=x;
  7. tailY[ 0]=y;
  8. int i= 0;
  9. /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
  10. for(i= 1; i<ntail;i++)
  11. {
  12. last2X = tailX[i];
  13. last2Y = tailY[i];
  14. tailX[i]=lastX;
  15. tailY[i]=lastY;
  16. lastX = last2X;
  17. lastY = last2Y;
  18. }

lastX lastY 用来存上一次的蛇头的位置。后面的 for 循环,通过tail 蛇的长度,把蛇上个状态给保存到数组tailX tailY里面。

完整代码


   
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <Windows.h>
  5. #include <time.h>
  6. #include <conio.h> /*键盘输入获取*/
  7. bool gameOver;
  8. bool stop = false;
  9. bool hit = false;
  10. /*游戏的边框大小*/
  11. const int width = 50;
  12. const int height = 20;
  13. /*蛇的坐标,食物的坐标还有分数*/
  14. int x,y,fruitX,fruitY,score;
  15. /*蛇每个点的坐标*/
  16. int tailX[ 200],tailY[ 200];
  17. /*蛇的默认长度*/
  18. int ntail= 3;
  19. typedef enum
  20. {
  21. STOP = 0,
  22. LEFT,
  23. RIGHT,
  24. UP,
  25. DOWN
  26. }Direction;
  27. Direction Dir;
  28. /*开始菜单*/
  29. void menu()
  30. {
  31. int a;
  32. printf( "------------------------------------------------------------------\n");
  33. printf( "| 贪吃蛇游戏 |\n");
  34. printf( "| 1) 新游戏 |\n");
  35. printf( "| 2) 开始边界 |\n");
  36. printf( "| 3) 退出游戏 |\n");
  37. printf( "------------------------------------------------------------------\n");
  38. printf( "---->请输入你的选择:");
  39. scanf( "%d", &a);
  40. }
  41. /*初始化状态*/
  42. void setup()
  43. {
  44. gameOver = false;
  45. /*根据当前时间设置“随机数种子”*/
  46. srand(time(NULL));
  47. Dir = STOP;
  48. /*贪吃蛇的位置,固定在中间*/
  49. x= width/ 2;
  50. y= height/ 2;
  51. /*食物的位置,位置是随机的*/
  52. fruitX = rand()%width;
  53. fruitY = rand()%height;
  54. score = 0;
  55. }
  56. /*绘制界面*/
  57. void draw()
  58. {
  59. if(stop == true)
  60. {
  61. return;
  62. }
  63. system( "cls"); /*清除屏幕*/
  64. printf( "分数:%d",score);
  65. printf( "\n");
  66. /*第一行*/
  67. int i;
  68. for(i= 0 ;i<width+ 1;i++)
  69. {
  70. printf( "-");
  71. }
  72. printf( "\n");
  73. /*画中间的画面*/
  74. int p;
  75. for(p= 0 ;p<height;p++) /*高度*/
  76. {
  77. int q;
  78. for(q= 0 ;q<width;q++) /*宽度*/
  79. {
  80. /*第一行最后已给字符*/
  81. if(q== 0 || q==width -1)
  82. {
  83. printf( "|");
  84. }
  85. if(p == fruitY && q == fruitX) /*食物的随机坐标*/
  86. {
  87. printf( "O");
  88. }
  89. else
  90. {
  91. int k= 0;
  92. bool print = false;
  93. /*贪吃蛇的长度 默认长度是 3*/
  94. for(k= 0;k<ntail;k++)
  95. {
  96. if(tailX[k]==q && tailY[k]==p)
  97. {
  98. printf( "*");
  99. print = true;
  100. }
  101. }
  102. /*如果这个位置打印了 * 就不要打印空格了*/
  103. if(! print)
  104. {
  105. printf( " ");
  106. }
  107. }
  108. }
  109. printf( "\n");
  110. }
  111. /*最后一行*/
  112. int j;
  113. for(j= 0 ;j<width+ 1;j++)
  114. {
  115. printf( "-");
  116. }
  117. }
  118. /*按键输入控制*/
  119. void input()
  120. {
  121. if(_kbhit())
  122. {
  123. /*获取键盘的输入字符*/
  124. switch(_getch())
  125. {
  126. case '4':
  127. case 75: /*左键*/
  128. Dir = LEFT;
  129. hit= true;
  130. break;
  131. case '8':
  132. case 72: /*上键*/
  133. Dir = UP;
  134. hit= true;
  135. break;
  136. case '6':
  137. case 77: /*右键*/
  138. Dir = RIGHT;
  139. hit= true;
  140. break;
  141. case '2':
  142. case 80: /*向下键盘键 */
  143. Dir = DOWN;
  144. hit= true;
  145. break;
  146. case 'x':
  147. case 27: /*ESE*/
  148. gameOver = true;
  149. break;
  150. case 32: /*空格 暂停键*/
  151. stop = !stop;
  152. break;
  153. }
  154. }
  155. else if(!hit && stop == false) /*如果没有改变方向*/
  156. {
  157. x++;
  158. }
  159. }
  160. /*判断贪吃蛇的长度*/
  161. void logic()
  162. {
  163. if(stop == true)
  164. {
  165. return;
  166. }
  167. /*把上一个位置记下*/
  168. int lastX = tailX[ 0];
  169. int lastY = tailY[ 0];
  170. int last2X, last2Y;
  171. /*重新获取当前的位置*/
  172. tailX[ 0]=x;
  173. tailY[ 0]=y;
  174. int i= 0;
  175. /*遍历整条蛇的长度 把 0 的位置空出来,其余蛇的位置往后面的空间移动*/
  176. for(i= 1; i<ntail;i++)
  177. {
  178. last2X = tailX[i];
  179. last2Y = tailY[i];
  180. tailX[i]=lastX;
  181. tailY[i]=lastY;
  182. lastX = last2X;
  183. lastY = last2Y;
  184. }
  185. /*根据方向来改变x y 的值*/
  186. switch(Dir)
  187. {
  188. case UP:
  189. y--;
  190. break;
  191. case DOWN:
  192. y++;
  193. break;
  194. case LEFT:
  195. x--;
  196. break;
  197. case RIGHT:
  198. x++;
  199. break;
  200. }
  201. if(x< 0 || width<x || y< 0 || height<y)
  202. {
  203. gameOver = true;
  204. /*清除屏幕*/
  205. system( "cls");
  206. printf( "------------------------------------------------------------------\n");
  207. printf( "| |\n");
  208. printf( "| |\n");
  209. printf( "| 游戏结束 |\n");
  210. printf( "| |\n");
  211. printf( "| |\n");
  212. printf( "------------------------------------------------------------------\n");
  213. }
  214. if(x==fruitX && y==fruitY)
  215. {
  216. /*吃了一个食物,蛇的长度增加1*/
  217. ntail++;
  218. score+= 10;
  219. /*更新下一个食物的位置*/
  220. fruitX = rand()%width;
  221. fruitY = rand()%height;
  222. }
  223. }
  224. int main()
  225. {
  226. # if 0
  227. while( 1)
  228. {
  229. printf( "%d\n",_getch());
  230. }
  231. #endif
  232. menu();
  233. setup();
  234. draw();
  235. /*循环画贪吃蛇的界面*/
  236. while(!gameOver)
  237. {
  238. draw();
  239. input();
  240. logic();
  241. Sleep( 70);
  242. }
  243. return 0;
  244. }

上面这段代码直接在Dev C++上面应该是可以运行的,很多人在知乎上私信问我,为什么我的贪吃蛇执行不了呢,可能就是平台不同,少了这个头文件,少了那个头文件,但是你为什么不能跟我一样,用Dev C++呢,轻量级,简单。代码的精髓是什么?我认为精髓一定是思想,不是你写了多少行代码,用了什么高端的IDE。

我自认为我的注释已经写得不错了,所以就没有什么好说明的了吧,有不明白的把代码过一下,至于屏幕刷新这个东西,如果只是用时间刷新就会闪屏,所以出现了一个双缓存,把要显示的东西送到一个buff里面去,另一个buff用来显示,这样就可以保证不会出现闪屏。除了写贪吃蛇,可以用这个方法写其他小程序,挺有意思的。

在知乎上,发起了一个C语言 100 行代码之内实现贪吃蛇的问题。我觉得很不错,里面很多同学的回复都非常赞,特别是叶大神的回复。

https://www.zhihu.com/question/360814879/answer/1013986215


扫码或长按关注

回复「 篮球的大肚子」进入技术群聊


转载:https://blog.csdn.net/weiqifa0/article/details/104404355
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场