C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次。

  是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第二天写了第二版和第三版。

  相信C语言写个小游戏或小项目是大多数计算机相关专业的学生都做的事情,但是作为一个数学专业的学生,我们教研室的老师对C语言的要求也就比较低了,大一没有让我们做个小项目实践一次。至今为止用C/C++做过的三个小项目(大作业),一个是外校同学让我帮忙写的学生信息管理系统(天呐,这名字都被大学用烂了...),一个是本校计院的同学让我帮忙写的链表设计的大作业,实话说,真的很无聊...

  最后一个小项目就是贪吃蛇了,比前两个有意思多了,强烈建议大学老师让学生做些简单的界面程序而非黑框框下的所谓管理系统....让学生体会到乐趣才是真谛啊。


  附:源码及游戏程序下载地址:链接:贪吃蛇 密码:v55s

  


  

 第一版

  首先是第一版的源码奉上,因为没有学过MFC,这一版是借鉴了其他网站上的C语言贪吃蛇算法思路和图形写成的。

  我认为这里的贪吃蛇算法思路非常棒,虽然不知道这种算法的来由但是我对此算法创始人由衷敬佩...

    这里的算法思路其实是将图上每一个点的二维坐标转换成一维序列,然后通过一维序列映射地图上的每一个坐标

    最让我敬佩的地方就是在蛇头重绘的时候,这里的贪吃蛇移动地图上的二维坐标和原始地图的一维序列将随着蛇头的移动而不断发生交替改变,以适应贪吃蛇循环队列的算法要求。

  操作说明:WSAD控制方向。

  

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <conio.h>
  4. #include <time.h>
  5. #include <windows.h>
  6.  
  7. //背景宽-高
  8. #define HEIGHT 20
  9. #define WIDTH 20
  10. //地图中心
  11. #define XCENTER HEIGHT/2
  12. #define YCENTER WIDTH/2
  13. //最大蛇长
  14. #define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
  15. //坐标->编号
  16. #define NUM(x,y) ((x-1)*(WIDTH-2)+(y-1))
  17.  
  18. //模型
  19. struct Model{
  20. char *ch;
  21. int color;
  22. char flag;
  23. }
  24. border = { "□", , },
  25. background = { "█", , },
  26. snakeHead = { "★", 0xE, },
  27. snakeBody = { "■", 0xE, },
  28. food = { "●", 0xC, };
  29.  
  30. int snakeLen = ; //贪吃蛇长度
  31.  
  32. //地图
  33. struct Map {
  34. int flag; //模型标识
  35. int num; //坐标编号
  36. }map[WIDTH][HEIGHT];
  37.  
  38. //坐标
  39. //贪吃蛇移动范围(循环队列),分数位置
  40. struct Coordinate{
  41. int x, y;
  42. }snake[SNAKE_MAXLEN], scorePos;
  43.  
  44. int score; //分数
  45. int header, tail; //蛇头蛇尾下标
  46. HANDLE hConsole;
  47.  
  48. void setCursor(int x, int y)
  49. {
  50. //参数x为行,y为列-与光标设置相反
  51. COORD coord;
  52. coord.X = *y; //宽字符决定占两列
  53. coord.Y = x;
  54. SetConsoleCursorPosition(hConsole, coord);
  55. }
  56.  
  57. void setColor(int color)
  58. {
  59. SetConsoleTextAttribute(hConsole, color);
  60. }
  61.  
  62. //随机生成食物
  63. void createFood()
  64. {
  65. int num; //新食物对应的坐标编号
  66. int range; //新食物所在范围
  67. srand((unsigned)time(NULL)); //初始种子
  68. range = SNAKE_MAXLEN - snakeLen; //食物生成范围
  69. if (tail < header)
  70. num = rand() % range + tail + ;
  71. else {
  72. num = rand() % range;
  73. if (num >= header)
  74. num += snakeLen;
  75. }
  76. //绘制食物
  77. int tx = snake[num].x;
  78. int ty = snake[num].y;
  79. setCursor(tx, ty);
  80. setColor(food.color);
  81. printf("%s", food.ch);
  82. map[tx][ty].flag = food.flag;
  83. }
  84.  
  85. //游戏结束
  86. void gameOver()
  87. {
  88. setCursor(XCENTER, YCENTER - );
  89. setColor(0xC);
  90.  
  91. printf("Game Over!");
  92. getch();
  93. exit(); //结束程序
  94. }
  95.  
  96. void move(char direction)
  97. {
  98. //新蛇头
  99. int tx = snake[header].x;
  100. int ty = snake[header].y;
  101. switch (direction)
  102. {
  103. case 'w':
  104. tx--; break;
  105. case 's':
  106. tx++; break;
  107. case 'a':
  108. ty--; break;
  109. case 'd':
  110. ty++; break;
  111. }
  112.  
  113. //判断是否会出界或撞到自己
  114. if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
  115. gameOver();
  116.  
  117. //新蛇头绘制(此时未refresh模型标识)
  118. setCursor(tx, ty);
  119. setColor(snakeHead.color);
  120. printf("%s", snakeHead.ch);
  121. //原蛇头重绘制
  122. setCursor(snake[header].x, snake[header].y);
  123. printf("%s", snakeBody.ch); //小方块
  124.  
  125. //蛇头更新-队首移动
  126. header = header == ? SNAKE_MAXLEN - : header - ;
  127. //旧编号位置更正
  128. int preNum = map[tx][ty].num; //蛇头位置旧编号
  129. snake[preNum].x = snake[header].x;
  130. snake[preNum].y = snake[header].y;
  131. map[snake[preNum].x][snake[preNum].y].num = preNum;
  132. //蛇头位置更正
  133. snake[header].x = tx;
  134. snake[header].y = ty;
  135. map[tx][ty].num = header; //蛇头位置新编号
  136.  
  137. //判断是否吃到食物
  138. if (map[tx][ty].flag == food.flag)
  139. {
  140. createFood(); //随机生成食物
  141. snakeLen++; //蛇身加长
  142. //更新-score
  143. setCursor(scorePos.x, scorePos.y);
  144. printf("%d", ++score);
  145. }
  146. else {
  147. //删除蛇尾
  148. setCursor(snake[tail].x, snake[tail].y);
  149. map[snake[tail].x][snake[tail].y].flag = background.flag;
  150. setColor(background.color);
  151. printf("%s", background.ch);
  152. tail = tail == ? SNAKE_MAXLEN - : tail - ;
  153. }
  154.  
  155. //更新-蛇头模型标识
  156. map[tx][ty].flag = snakeBody.flag;
  157. }
  158.  
  159. //初始化界面
  160. void init()
  161. {
  162. CONSOLE_CURSOR_INFO cci; //光标信息
  163. header = ;
  164. tail = snakeLen - ;
  165.  
  166. //设置光标不可见
  167. hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  168. GetConsoleCursorInfo(hConsole, &cci);
  169. cci.bVisible = ;
  170. SetConsoleCursorInfo(hConsole, &cci);
  171.  
  172. //dos命令设置窗口大小
  173. system("mode con:cols=100 lines=32");
  174.  
  175. //绘制背景
  176. for (int x = ; x < HEIGHT; x++)
  177. {
  178. for (int y = ; y < WIDTH; y++)
  179. {
  180. if (x == || y == || x == HEIGHT - || y == WIDTH - )
  181. {
  182. map[x][y].flag = border.flag;
  183. setColor(border.color);
  184. printf("%s", border.ch);
  185. }
  186. else {
  187. int num = NUM(x,y);
  188. snake[num].x = x;
  189. snake[num].y = y;
  190. //背景设置
  191. map[x][y].num = num;
  192. map[x][y].flag = background.flag;
  193. setColor(background.color);
  194. printf("%s", background.ch);
  195. }
  196. }
  197. printf("\n");
  198. }
  199.  
  200. //绘制初始贪吃蛇
  201. setCursor(XCENTER, YCENTER - snakeLen / );
  202. header = NUM(XCENTER, YCENTER - ); //蛇头位置
  203. tail = header + snakeLen - ;
  204. setColor(snakeBody.color);
  205. for (int i = header; i <= tail; i++)
  206. {
  207. if (i == header) printf("%s", snakeHead.ch);
  208. else printf("%s", snakeBody.ch);
  209. map[snake[i].x][snake[i].y].flag = snakeBody.flag;
  210. }
  211.  
  212. //随机生成食物
  213. createFood();
  214.  
  215. //其他信息
  216. setCursor(XCENTER - , WIDTH + );
  217. printf(" score: 0");
  218. setCursor(XCENTER, WIDTH + );
  219. printf(" Author: InkMark");
  220. setCursor(XCENTER + , WIDTH + );
  221. printf(" Blog: www.cnblogs.com/inkblots");
  222. //分数位置
  223. scorePos.x = XCENTER - ;
  224. scorePos.y = WIDTH + ;
  225. }
  226.  
  227. int main()
  228. {
  229. //方向及其他初始化
  230. char direction = 'a';
  231. init();
  232.  
  233. char ch = tolower(getch());
  234. if (ch == 'a' || ch == 'w' || ch == 's')
  235. direction = ch;
  236.  
  237. while () {
  238. if (kbhit()) {
  239. ch = tolower(getch());
  240. if (ch == ' ')
  241. ch = getch(); //实现空格-暂停
  242. if(ch == 'a' || ch == 'd' || ch == 'w' || ch=='s')
  243. if (ch + direction != && ch + direction != )
  244. direction = ch; //不为反向时改变方向
  245. }
  246. move(direction);
  247. Sleep();
  248. }
  249.  
  250. return ;
  251. }

= 。=

  


第二版:

  第二版在第一版的算法基础上改进了图形界面和源码管理,新增了“加速”技能(比较方便实现)。

  控制方向也改为方向键了。

  第二版源码分为三个文件,运行源码需要链接一次。

  先是一个头文件,定义了要用到的库文件,常用常量和结构体,以及声明main中要用到的函数

  

  1. #ifndef CATALOG_H
  2. #define CATALOG_H
  3.  
  4. #include<stdio.h>
  5. #include<conio.h>
  6. #include<time.h>
  7. #include<windows.h>
  8.  
  9. //背景上下伸展长度
  10. #define TOP_EXTEND 3
  11. #define BOTTOM_EXTEND 3
  12. //背景宽-高
  13. #define WIDTH 33
  14. #define HEIGHT 20
  15. //地图中心
  16. #define XCENTER ((HEIGHT + 1)/2 + TOP_EXTEND)
  17. #define YCENTER (WIDTH + 1)/2
  18. //最大蛇长
  19. #define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
  20. //坐标->序号
  21. #define ORDER(x,y) ((x - TOP_EXTEND - 1) * (WIDTH - 2) + (y - 1))
  22. //点:在移动范围内
  23. #define IN_RANGE(x,y) (x > TOP_EXTEND && x < HEIGHT + TOP_EXTEND - 1 && y > 0 && y < WIDTH - 1)
  24. //默认暂停时间
  25. #define PAUSE_TIME 500
  26.  
  27. /*全局变量*/
  28. extern int snakeLen;
  29. extern int direction;
  30. extern int header, tail;
  31. extern int score;
  32. extern int skill;
  33. extern int pauseTime;
  34. extern HANDLE hConsole;
  35.  
  36. //模型
  37. typedef struct Model {
  38. char *ch;
  39. int color;
  40. int flag;
  41. }Model;
  42.  
  43. //地图
  44. typedef struct Map {
  45. int flag; //模型标识
  46. int order; //序号
  47. }Map;
  48.  
  49. //坐标
  50. //贪吃蛇移动范围(循环队列),分数位置
  51. typedef struct Coordinate {
  52. int x, y;
  53. }Coordinate;
  54.  
  55. /******界面设定******/
  56.  
  57. void setCursor(int x, int y);
  58.  
  59. void setColor(int color);
  60.  
  61. void control(char ch);
  62.  
  63. /******框架及功能******/
  64.  
  65. void init();
  66.  
  67. int move(char direction);
  68.  
  69. void createFood();
  70.  
  71. #endif

catalog.h

  第二个是功能部分源码

  1. #include "catalog.h"
  2.  
  3. Model border = { NULL, 0x7, },
  4. snakeHead = { "★", 0xE, },
  5. snakeBody = { "■", 0xE, },
  6. food = { "●", 0xC, };
  7.  
  8. Map map[HEIGHT][WIDTH];
  9.  
  10. Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
  11.  
  12. /************游戏界面设定************/
  13.  
  14. //隐藏光标
  15. void hideCursor()
  16. {
  17. CONSOLE_CURSOR_INFO cci; //光标信息
  18. hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  19. GetConsoleCursorInfo(hConsole, &cci);
  20. cci.bVisible = ;
  21. SetConsoleCursorInfo(hConsole, &cci);
  22. }
  23.  
  24. //设置光标位置
  25. void setCursor(int x, int y)
  26. {
  27. //参数x为行,y为列-与光标设置相反
  28. COORD coord;
  29. coord.X = * y; //宽字符决定占两列
  30. coord.Y = x;
  31. SetConsoleCursorPosition(hConsole, coord);
  32. }
  33.  
  34. //设置文字颜色
  35. void setColor(int color)
  36. {
  37. SetConsoleTextAttribute(hConsole, color);
  38. }
  39.  
  40. //绘制游戏窗口(包括dos环境初始窗口)
  41. void createWindow()
  42. {
  43. //dos命令设置窗口大小
  44. system("mode con:cols=72 lines=27");
  45.  
  46. //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
  47. setColor(0x7);
  48. printf("╔════════════════╦════════════════╗\n"); //0~34
  49. for (int i = ; i < TOP_EXTEND; i++)
  50. printf("║ ║ ║\n");
  51. printf("╠════════════════╩════════════════╣\n");
  52. for (int i = ; i < HEIGHT - ; i++)
  53. printf("║ ║\n");
  54. printf("╠═════════════════════════════════╣\n");
  55. for (int i = ; i < BOTTOM_EXTEND; i++)
  56. printf("║ ║\n");
  57. printf("╚═════════════════════════════════╝\n");
  58. setCursor(HEIGHT + TOP_EXTEND, );
  59. printf(" 操作指南:方向键控制,空格可暂停,5分后可获得技能.");
  60. setCursor(HEIGHT + TOP_EXTEND + , );
  61. printf(" Version : 2.0");
  62.  
  63. for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
  64. {
  65. for (int y = ; y < WIDTH; y++)
  66. if (IN_RANGE(x, y))
  67. {
  68. int order = ORDER(x, y);
  69. snake[order].x = x;
  70. snake[order].y = y;
  71. //背景设置
  72. map[x][y].order = order;
  73. map[x][y].flag = ;
  74. }
  75. else map[x][y].flag = border.flag;
  76. }
  77. //其他信息
  78. setColor(0x7);
  79. setCursor(, );
  80. printf(" 你的分数:0");
  81. setCursor(, );
  82. printf(" 技能:无");
  83. setCursor(, YCENTER + );
  84. printf(" Author: InkMark");
  85. setCursor(, YCENTER + );
  86. printf(" Blog: www.cnblogs.com/inkblots");
  87.  
  88. //分数位置
  89. scorePos.x = ; scorePos.y = ;
  90. skillPos.x = ; skillPos.y = ;
  91. }
  92.  
  93. //控制键
  94. void control(char ch)
  95. {
  96. //本应取方向键高位再取低位,在此以简便为主
  97. if (ch != -) return;
  98. ch = getch();
  99. //上72下80左75右77
  100. if (ch == || ch == || ch == || ch == ) //低位相同
  101. if (ch + direction != ) direction = ch; //不为反向时改变方向
  102. }
  103.  
  104. /************游戏信息输出************/
  105.  
  106. void getSkill()
  107. {
  108. setCursor(skillPos.x, skillPos.y);
  109. printf("加速(S键)");
  110. skill = ; //加速技能开启
  111. }
  112.  
  113. void alterScore(int addition)
  114. {
  115. score += addition;
  116. if (score >= )
  117. getSkill();
  118. setCursor(scorePos.x, scorePos.y);
  119. setColor(0x7);
  120. printf("%d", score);
  121. }
  122.  
  123. void gameOver()
  124. {
  125. if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
  126. {
  127. system("CLS");
  128. return;
  129. }
  130.  
  131. exit();
  132. }
  133.  
  134. /************游戏框架及功能************/
  135.  
  136. //变量初始化及界面初始化
  137. void init()
  138. {
  139. pauseTime = PAUSE_TIME;
  140. skill = ;
  141. score = ;
  142. snakeLen = ;
  143. header = ;
  144. tail = snakeLen - ;
  145.  
  146. hideCursor();//隐藏光标
  147. createWindow(); //绘制背景
  148. }
  149.  
  150. //贪吃蛇移动
  151. //return:1为成功,0为失败
  152. int move(char direction)
  153. {
  154. //新蛇头
  155. int tx = snake[header].x;
  156. int ty = snake[header].y;
  157. //上72下80左75右77
  158. switch (direction)
  159. {
  160. case : tx--; break;
  161. case : tx++; break;
  162. case : ty--; break;
  163. case : ty++; break;
  164. }
  165.  
  166. //判断是否撞墙或撞到自己
  167. if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
  168. {
  169. gameOver();
  170. return ;
  171. }
  172.  
  173. //新蛇头绘制(此时未refresh模型标识)
  174. setCursor(tx, ty);
  175. setColor(snakeHead.color);
  176. printf("%s", snakeHead.ch);
  177. //原蛇头重绘制
  178. setCursor(snake[header].x, snake[header].y);
  179. printf("%s", snakeBody.ch);
  180.  
  181. //蛇头更新-队首移动
  182. header = header == ? SNAKE_MAXLEN - : header - ;
  183. //旧编号位置更正
  184. int preNum = map[tx][ty].order; //蛇头位置旧编号
  185. snake[preNum].x = snake[header].x;
  186. snake[preNum].y = snake[header].y;
  187. map[snake[preNum].x][snake[preNum].y].order = preNum;
  188. //蛇头位置更正
  189. snake[header].x = tx;
  190. snake[header].y = ty;
  191. map[tx][ty].order = header; //蛇头位置新编号
  192.  
  193. //判断是否吃到食物
  194. if (map[tx][ty].flag == food.flag)
  195. {
  196. snakeLen++; //蛇身加长
  197. createFood(); //随机生成食物
  198. //更新-score
  199. alterScore();
  200. }
  201. else {
  202. //删除蛇尾
  203. setCursor(snake[tail].x, snake[tail].y);
  204. map[snake[tail].x][snake[tail].y].flag = ;
  205. printf(" ");
  206. tail = tail == ? SNAKE_MAXLEN - : tail - ;
  207. }
  208.  
  209. //更新-蛇头模型标识
  210. map[tx][ty].flag = snakeBody.flag;
  211.  
  212. return ;
  213. }
  214.  
  215. //随机生成食物
  216. void createFood()
  217. {
  218. int order; //新食物对应的坐标编号
  219. int range; //新食物所在范围
  220. srand((unsigned)time(NULL)); //初始种子
  221. range = SNAKE_MAXLEN - snakeLen; //食物生成范围
  222. if (tail < header)
  223. order = rand() % range + tail + ;
  224. else {
  225. order = rand() % range;
  226. if (order >= header)
  227. order += snakeLen;
  228. }
  229. //绘制食物
  230. int tx = snake[order].x;
  231. int ty = snake[order].y;
  232. setCursor(tx, ty);
  233. setColor(food.color);
  234. printf("%s", food.ch);
  235. map[tx][ty].flag = food.flag;
  236. }

Util.c

  第三个是主函数及初始化部分

  1. #include "catalog.h"
  2.  
  3. int snakeLen; //贪吃蛇长度
  4. int direction; //贪吃蛇移动方向
  5. int header, tail; //蛇头蛇尾下标
  6. int score; //分数
  7. int skill; //技能开关
  8. int pauseTime; //暂停时间(Ms)
  9. HANDLE hConsole;
  10.  
  11. extern Model border, snakeHead, snakeBody, food;
  12. extern Map map[HEIGHT][WIDTH];
  13. extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
  14.  
  15. //初始化方案
  16. void scheme()
  17. {
  18. //变量初始化及界面初始化
  19. init();
  20.  
  21. //绘制初始贪吃蛇
  22. setCursor(XCENTER, YCENTER - snakeLen / );
  23. header = ORDER(XCENTER, YCENTER - snakeLen / ); //蛇头位置
  24. tail = header + snakeLen - ;
  25. setColor(snakeBody.color);
  26. for (int i = header; i <= tail; i++)
  27. {
  28. if (i == header) printf("%s", snakeHead.ch);
  29. else printf("%s", snakeBody.ch);
  30. map[snake[i].x][snake[i].y].flag = snakeBody.flag;
  31. }
  32.  
  33. //随机生成食物
  34. createFood();
  35.  
  36. //初始方向处理
  37. direction = ;
  38. char ch = getch();
  39. control(ch);
  40. }
  41.  
  42. int main()
  43. {
  44. //初始方案
  45. scheme();
  46.  
  47. while () {
  48. if (kbhit()) {
  49. char ch = getch();
  50. if (ch == ' ') MessageBox(NULL, " 暂停中...\n 请单击确定继续游戏", "暂停游戏", MB_OK);
  51. if (skill == && (ch == 's' || ch == 'S'))
  52. pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / : PAUSE_TIME;
  53. else control(ch); //控制方向
  54. }
  55. if (move(direction))
  56. Sleep(pauseTime);
  57. else scheme();
  58. }
  59.  
  60. return ;
  61. }

SnakeMain.c


第三版:

  第三版加入了菜单,优化了部分界面,并将游戏分为两个基本模式。

  

  和第二版一样,分为三个文件

  头文件:

  

  1. #ifndef CATALOG_H
  2. #define CATALOG_H
  3.  
  4. #include<stdio.h>
  5. #include<conio.h>
  6. #include<time.h>
  7. #include<windows.h>
  8.  
  9. //背景上下伸展长度
  10. #define TOP_EXTEND 3
  11. #define BOTTOM_EXTEND 3
  12. //背景宽-高
  13. #define WIDTH 33
  14. #define HEIGHT 20
  15. //地图中心
  16. #define XCENTER ((HEIGHT + 1)/2 + TOP_EXTEND)
  17. #define YCENTER (WIDTH + 1)/2
  18. //最大蛇长
  19. #define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
  20. //坐标->序号
  21. #define ORDER(x,y) ((x - TOP_EXTEND - 1) * (WIDTH - 2) + (y - 1))
  22. //点:在移动范围内
  23. #define IN_RANGE(x,y) (x > TOP_EXTEND && x < HEIGHT + TOP_EXTEND - 1 && y > 0 && y < WIDTH - 1)
  24. //默认暂停时间
  25. #define PAUSE_TIME 500
  26.  
  27. /*全局变量*/
  28. extern int snakeLen;
  29. extern int direction;
  30. extern int header, tail;
  31. extern int score;
  32. extern int skill;
  33. extern int pauseTime;
  34. extern int mode;
  35. extern HANDLE hConsole;
  36.  
  37. //模型
  38. typedef struct Model {
  39. char *ch;
  40. int color;
  41. int flag;
  42. }Model;
  43.  
  44. //地图
  45. typedef struct Map {
  46. int flag; //模型标识
  47. int order; //序号
  48. }Map;
  49.  
  50. //坐标
  51. //贪吃蛇移动范围(循环队列),分数位置
  52. typedef struct Coordinate {
  53. int x, y;
  54. }Coordinate;
  55.  
  56. /******界面设定******/
  57.  
  58. extern void setCursor(int x, int y);
  59.  
  60. extern void setColor(int color);
  61.  
  62. extern void control(char ch);
  63.  
  64. /******框架及功能******/
  65.  
  66. extern void init();
  67.  
  68. extern int move(char direction);
  69.  
  70. extern void createFood();
  71.  
  72. #endif

catalog.h

  功能文件:

  1. #include "catalog.h"
  2.  
  3. Model border = { NULL, 0x7, },
  4. snakeHead = { "★", 0xE, },
  5. snakeBody = { "■", 0xE, },
  6. food = { "●", 0xC, };
  7.  
  8. Map map[HEIGHT][WIDTH];
  9.  
  10. Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos, dotPos;
  11.  
  12. #define UP 4 //向上偏移量
  13. #define LEFT 6 //左移偏移量
  14.  
  15. /************游戏界面设定************/
  16.  
  17. //隐藏光标
  18. void hideCursor()
  19. {
  20. CONSOLE_CURSOR_INFO cci; //光标信息
  21. hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  22. GetConsoleCursorInfo(hConsole, &cci);
  23. cci.bVisible = ;
  24. SetConsoleCursorInfo(hConsole, &cci);
  25. }
  26.  
  27. //设置光标位置
  28. void setCursor(int x, int y)
  29. {
  30. //参数x为行,y为列-与光标设置相反
  31. COORD coord;
  32. coord.X = * y; //宽字符决定占两列
  33. coord.Y = x;
  34. SetConsoleCursorPosition(hConsole, coord);
  35. }
  36.  
  37. //设置文字颜色
  38. void setColor(int color)
  39. {
  40. SetConsoleTextAttribute(hConsole, color);
  41. }
  42.  
  43. //绘制游戏窗口(包括dos环境初始窗口)
  44. void createWindow()
  45. {
  46. //dos命令设置窗口大小
  47. system("mode con:cols=72 lines=28");
  48.  
  49. //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
  50. setColor(0x7);
  51. printf("╔════════════════╦════════════════╗\n"); //0~34
  52. for (int i = ; i < TOP_EXTEND; i++)
  53. printf("║ ║ ║\n");
  54. printf("╠════════════════╩════════════════╣\n");
  55. for (int i = ; i < HEIGHT - ; i++)
  56. printf("║ ║\n");
  57. printf("╠═════════════════════════════════╣\n");
  58. for (int i = ; i < BOTTOM_EXTEND; i++)
  59. printf("║ ║\n");
  60. printf("╚═════════════════════════════════╝\n");
  61. setCursor(HEIGHT + TOP_EXTEND, );
  62. printf(" 操作指南:上下键及回车键选择.");
  63. setCursor(HEIGHT + TOP_EXTEND + , );
  64. printf(" Version : 3.0");
  65.  
  66. for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
  67. {
  68. for (int y = ; y < WIDTH; y++)
  69. if (IN_RANGE(x, y))
  70. {
  71. int order = ORDER(x, y);
  72. snake[order].x = x;
  73. snake[order].y = y;
  74. //背景设置
  75. map[x][y].order = order;
  76. map[x][y].flag = ;
  77. }
  78. else map[x][y].flag = border.flag;
  79. }
  80. //其他信息
  81. setColor(0x7);
  82. setCursor(, );
  83. printf(" 你的分数:0");
  84. setCursor(, );
  85. printf(" 技能:无");
  86. setCursor(, YCENTER + );
  87. printf(" Author: InkMark");
  88. setCursor(, YCENTER + );
  89. printf(" Blog: www.cnblogs.com/inkblots");
  90.  
  91. //分数位置
  92. scorePos.x = ; scorePos.y = ;
  93. skillPos.x = ; skillPos.y = ;
  94. }
  95.  
  96. void menuButton(char ch)
  97. {
  98. int tx = dotPos.x;
  99. int ty = dotPos.y;
  100. if (ch == ) tx--;
  101. else tx++;
  102.  
  103. if (tx > XCENTER - UP && tx < XCENTER - UP + )
  104. {
  105. setCursor(dotPos.x, dotPos.y);
  106. printf(" ");
  107. setCursor(tx, ty);
  108. printf("●");
  109. dotPos.x = tx;
  110. dotPos.y = ty;
  111. }
  112. }
  113.  
  114. //绘制菜单并进行选择
  115. void menu()
  116. {
  117. //╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
  118. setCursor(XCENTER - UP, YCENTER - LEFT);
  119. printf("╔═════════╗"); //
  120. for (int i = ; i <= ; i++)
  121. {
  122. setCursor(XCENTER - UP + i, YCENTER - LEFT);
  123. printf("║ ║");
  124. }
  125. setCursor(XCENTER - UP + , YCENTER - LEFT);
  126. printf("╚═════════╝");
  127.  
  128. dotPos.x = XCENTER - UP + ;
  129. dotPos.y = YCENTER - ;
  130. setCursor(dotPos.x, dotPos.y);
  131. printf("● 1.死亡模式");
  132. setCursor(XCENTER - UP + , YCENTER - );
  133. printf("2.技能模式");
  134. setCursor(XCENTER - UP + , YCENTER - );
  135. printf("3.退出游戏");
  136.  
  137. char ch;
  138. while ((ch = getch()) != ) //确定键:13
  139. {
  140. if (ch != -) continue;
  141. ch = getch();
  142. if (ch == || ch == )
  143. menuButton(ch);
  144. }
  145.  
  146. for (int i = ; i < ; i++)
  147. {
  148. setCursor(XCENTER - UP + i, YCENTER - LEFT);
  149. printf(" ");
  150. }
  151.  
  152. mode = dotPos.x - XCENTER + UP;
  153. if (mode == ) exit();
  154. }
  155.  
  156. //控制键
  157. void control(char ch)
  158. {
  159. //本应取方向键高位再取低位,在此以简便为主
  160. if (ch != -) return;
  161. ch = getch();
  162. //上72下80左75右77
  163. if (ch == || ch == || ch == || ch == ) //低位相同
  164. if (ch + direction != )
  165. direction = ch; //不为反向时改变方向
  166. }
  167.  
  168. /************游戏信息输出************/
  169.  
  170. void getSkill()
  171. {
  172. setCursor(skillPos.x, skillPos.y);
  173. printf("加速(S键)");
  174. skill = ; //加速技能开启
  175. }
  176.  
  177. void alterScore(int addition)
  178. {
  179. score += addition;
  180. if (mode == && score >= )
  181. getSkill();
  182. setCursor(scorePos.x, scorePos.y);
  183. setColor(0x7);
  184. printf("%d", score);
  185. }
  186.  
  187. void printInfo()
  188. {
  189. //╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
  190. int col = ;
  191. setCursor(HEIGHT + TOP_EXTEND - , col);
  192. printf("╦");
  193. setCursor(HEIGHT + TOP_EXTEND, col);
  194. printf("║");
  195. setCursor(HEIGHT + TOP_EXTEND + , col);
  196. printf("║ 模 式");
  197. if (mode == ) {
  198.  
  199. setCursor(HEIGHT + TOP_EXTEND, );
  200. printf(" 操作指南:方向键控制,空格可暂停.");
  201. setCursor(HEIGHT + TOP_EXTEND, col + );
  202. printf(" 无 尽");
  203. }
  204. else {
  205. setCursor(HEIGHT + TOP_EXTEND, );
  206. printf(" 操作指南:方向键控制,空格可暂停,8分后有惊喜.");
  207. setCursor(HEIGHT + TOP_EXTEND, col + );
  208. printf(" 技 能");
  209. }
  210. setCursor(HEIGHT + TOP_EXTEND + , col);
  211. printf("╩");
  212. }
  213.  
  214. void gameOver()
  215. {
  216. if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
  217. {
  218. system("CLS");
  219. return;
  220. }
  221.  
  222. exit();
  223. }
  224.  
  225. /************游戏框架及功能************/
  226.  
  227. //变量初始化及界面初始化
  228. void init()
  229. {
  230. pauseTime = PAUSE_TIME;
  231. skill = ;
  232. score = ;
  233. snakeLen = ;
  234. header = ;
  235. tail = snakeLen - ;
  236.  
  237. hideCursor();//隐藏光标
  238. createWindow(); //绘制背景
  239.  
  240. menu(); //菜单操作
  241.  
  242. printInfo();
  243. }
  244.  
  245. //贪吃蛇移动
  246. //return:1为成功,0为失败
  247. int move(char direction)
  248. {
  249. //新蛇头
  250. int tx = snake[header].x;
  251. int ty = snake[header].y;
  252. //上72下80左75右77
  253. switch (direction)
  254. {
  255. case : tx--; break;
  256. case : tx++; break;
  257. case : ty--; break;
  258. case : ty++; break;
  259. }
  260.  
  261. //判断是否撞墙或撞到自己
  262. if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
  263. {
  264. gameOver();
  265. return ;
  266. }
  267.  
  268. //新蛇头绘制(此时未refresh模型标识)
  269. setCursor(tx, ty);
  270. setColor(snakeHead.color);
  271. printf("%s", snakeHead.ch);
  272. //原蛇头重绘制
  273. setCursor(snake[header].x, snake[header].y);
  274. printf("%s", snakeBody.ch);
  275.  
  276. //蛇头更新-队首移动
  277. header = header == ? SNAKE_MAXLEN - : header - ;
  278. //旧编号位置更正
  279. int preNum = map[tx][ty].order; //蛇头位置旧编号
  280. snake[preNum].x = snake[header].x;
  281. snake[preNum].y = snake[header].y;
  282. map[snake[preNum].x][snake[preNum].y].order = preNum;
  283. //蛇头位置更正
  284. snake[header].x = tx;
  285. snake[header].y = ty;
  286. map[tx][ty].order = header; //蛇头位置新编号
  287.  
  288. //判断是否吃到食物
  289. if (map[tx][ty].flag == food.flag)
  290. {
  291. snakeLen++; //蛇身加长
  292. createFood(); //随机生成食物
  293. //更新-score
  294. if(pauseTime == PAUSE_TIME) alterScore();
  295. else alterScore();
  296. }
  297. else {
  298. //删除蛇尾
  299. setCursor(snake[tail].x, snake[tail].y);
  300. map[snake[tail].x][snake[tail].y].flag = ;
  301. printf(" ");
  302. tail = tail == ? SNAKE_MAXLEN - : tail - ;
  303. }
  304.  
  305. //更新-蛇头模型标识
  306. map[tx][ty].flag = snakeBody.flag;
  307.  
  308. return ;
  309. }
  310.  
  311. //随机生成食物
  312. void createFood()
  313. {
  314. int order; //新食物对应的坐标编号
  315. int range; //新食物所在范围
  316. srand((unsigned)time(NULL)); //初始种子
  317. range = SNAKE_MAXLEN - snakeLen; //食物生成范围
  318. if (tail < header)
  319. order = rand() % range + tail + ;
  320. else {
  321. order = rand() % range;
  322. if (order >= header)
  323. order += snakeLen;
  324. }
  325. //绘制食物
  326. int tx = snake[order].x;
  327. int ty = snake[order].y;
  328. setCursor(tx, ty);
  329. setColor(food.color);
  330. printf("%s", food.ch);
  331. map[tx][ty].flag = food.flag;
  332. }

Util.c

  主文件:

 

  1. #include "catalog.h"
  2.  
  3. int snakeLen; //贪吃蛇长度
  4. int direction; //贪吃蛇移动方向
  5. int header, tail; //蛇头蛇尾下标
  6. int score; //分数
  7. int skill; //技能开关
  8. int pauseTime; //暂停时间(Ms)
  9. int mode;
  10. HANDLE hConsole;
  11.  
  12. extern Model border, snakeHead, snakeBody, food;
  13. extern Map map[HEIGHT][WIDTH];
  14. extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
  15.  
  16. //初始化方案
  17. void scheme()
  18. {
  19. //变量初始化及界面初始化
  20. init();
  21.  
  22. //绘制初始贪吃蛇
  23. setCursor(XCENTER, YCENTER - snakeLen / );
  24. header = ORDER(XCENTER, YCENTER - snakeLen / ); //蛇头位置
  25. tail = header + snakeLen - ;
  26. setColor(snakeBody.color);
  27. for (int i = header; i <= tail; i++)
  28. {
  29. if (i == header) printf("%s", snakeHead.ch);
  30. else printf("%s", snakeBody.ch);
  31. map[snake[i].x][snake[i].y].flag = snakeBody.flag;
  32. }
  33.  
  34. //随机生成食物
  35. createFood();
  36.  
  37. //初始方向处理
  38. direction = ;
  39. char ch = getch();
  40. control(ch);
  41. }
  42.  
  43. int main()
  44. {
  45. //初始方案
  46. scheme();
  47.  
  48. while () {
  49. if (kbhit()) {
  50. char ch = getch();
  51. if (ch == ' ') MessageBox(NULL, " 暂停中...\n 请单击确定继续游戏", "暂停游戏", MB_OK);
  52. if (mode == && skill == && (ch == 's' || ch == 'S'))
  53. pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / : PAUSE_TIME;
  54. else control(ch); //控制方向
  55. }
  56. if (move(direction))
  57. Sleep(pauseTime);
  58. else scheme();
  59. }
  60.  
  61. return ;
  62. }

SnakeMain.c

小项目特供 贪吃蛇游戏(基于C语言)的更多相关文章

  1. 基于React的贪吃蛇游戏的设计与实现

    代码地址如下:http://www.demodashi.com/demo/11818.html 贪吃蛇小游戏(第二版) 一年半前层用react写过贪吃蛇小游戏https://github.com/ca ...

  2. 【C语言项目】贪吃蛇游戏(上)

    目录 00. 目录 01. 开发背景 02. 功能介绍 03. 欢迎界面设计 3.1 常用终端控制函数 3.2 设置文本颜色函数 3.3 设置光标位置函数 3.4 绘制字符画(蛇) 3.5 欢迎界面函 ...

  3. Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录

    一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...

  4. WebGL实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  5. 100行JS实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  6. 「JavaScript」手起刀落-一起来写经典的贪吃蛇游戏

    回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效 ...

  7. Love2D游戏引擎制作贪吃蛇游戏

    代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查 ...

  8. AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题

    在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...

  9. Qt 学习之路 2(34):贪吃蛇游戏(4)

    Qt 学习之路 2(34):贪吃蛇游戏(4) 豆子 2012年12月30日 Qt 学习之路 2 73条评论 这将是我们这个稍大一些的示例程序的最后一部分.在本章中,我们将完成GameControlle ...

随机推荐

  1. zookeeper原理(转)

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等.Zookeeper是hadoop的一个子项目,其 ...

  2. angularjs 过滤器详解

    https://segmentfault.com/a/1190000002758481     app.controller('testC',function($scope,$filter){ $sc ...

  3. SpringMVC应用

    SpringMVC的核心是DispatcherServlet,这个Servlet充当SpringMVC的前端控制器. SpringMVC是多线程的吗??? 控制器是一个用于处理请求的Spring组件. ...

  4. jquery 选择器 -高级使用 新的 心得

    jQuery的each函数: each函数等同于c语言中的for函数: 里面每次循环的 "context 上下文" == 当前的dom ,可以使用this, 也可以使用$(this ...

  5. PHP 5.5 新特性

    文章转自:http://wulijun.github.io/2013/07/17/whats-new-in-php-5-5.html http://www.cnblogs.com/yjf512/p/3 ...

  6. 系统研究Airbnb开源项目airflow

    开源项目airflow的一点研究 调研了一些几个调度系统, airflow 更满意一些. 花了些时间写了这个博文, 这应该是国内技术圈中最早系统性研究airflow的文章了.  转载请注明出处 htt ...

  7. [原] Intellij IDEA开发Android,祝还在使用eclipse的早日脱离苦海

    注: 现在推荐使用Android Studio,以后google在Android Studio上个性差异化的东西越来越多, 所以越早使用Android Studio越好,看看更新文档,使我们开发更方便 ...

  8. CSS hack 汇总

    1, IE条件注释法,微软官方推荐的hack方式. <!]> IE6以及IE6以上版本可识别 <![endif]--> <!]> 仅IE7可识别 <![end ...

  9. iOS: 如何正确的绘制1像素的线

    iOS 绘制1像素的线 一.Point Vs Pixel iOS中当我们使用Quartz,UIKit,CoreAnimation等框架时,所有的坐标系统采用Point来衡量.系统在实际渲染到设置时会帮 ...

  10. POJ 1019 Number Sequence

    找规律,先找属于第几个循环,再找属于第几个数的第几位...... Number Sequence Time Limit: 1000MS Memory Limit: 10000K Total Submi ...