参考视频:https://www.bilibili.com/video/av29580072/?p=1
GreedySnake.h
1 #ifndef GREEDYSNAKE_H_INCLUDED
2 #define GREEDYSNAKE_H_INCLUDED
3
4
5 #define SNAKE_LENGTH 20 //蛇的长度最大为20
6 #define true 1
7 #define false 0
8 enum {UP = -1, DOWN = 1, LEFT = -2, RIGHT = 2};
9
10 typedef int bool;
11
12 void FirstPage(); //设置起始游戏界面
13 void TestSpace(); //按空格开始游戏
14 void ShowBackground(); //展示游戏背景
15 void SetSnakeRandPos(); //为蛇产生一个随机的位置
16 void DrawSnake(); //画蛇
17 void SnakeMove(); //蛇动
18 void DestroySnake(); //销毁蛇
19 void ChangeDir(); //蛇随着方向键动起来
20 bool IsSnakeDie(); //判断蛇是否死亡
21 void ProduceFood(); //随机位置产生食物
22 void SnakeGrowUp(); //蛇变长
23 void PrintScore(); //打印分数
24
25
26 #endif // GREEDYSNAKE_H_INCLUDED
GreedySnake.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <conio.h>
5 #include <windows.h>
6 #include <time.h>
7 #include "GreedySnake.h"
8
9 //把所有元素置为0
10 //snake[0][0]表示蛇头的行,snake[0][1]表示蛇头的列,snake[0][2]表示蛇头移动的方向
11 int g_arrSnake[SNAKE_LENGTH][3] = { 0 };
12
13 int g_iSnakeLength = 2; //初始长度为3,但数组下标从0开始,故此处为2
14
15 char g_arrBackGround[20][50] =
16 {
17 "████████████████████████\n", //一个█占两个字节,占两个字符的位置
18 "█ █\n",
19 "█ █\n",
20 "█ █\n",
21 "█ █\n",
22 "█ █\n",
23 "█ █\n",
24 "█ █\n",
25 "█ █\n",
26 "█ █\n",
27 "█ █\n",
28 "█ █\n",
29 "█ █\n",
30 "█ █\n",
31 "█ █\n",
32 "█ █\n",
33 "█ █\n",
34 "█ █\n",
35 "█ █\n",
36 "████████████████████████\n"
37 };
38
39 int g_iSnakeDir = LEFT; //蛇的方向,默认向左
40 bool g_bIsProFood = true; //蛇产生食物的标记
41 int g_iRow; //食物的行坐标
42 int g_iCol; //食物的列坐标
43
44 int g_iScore = 0; //分数
45
46
47
48 void FirstPage() //设置起始游戏界面
49 {
50 for (int i = 0; i < 20; ++i)
51 printf(" ");
52 for (int i = 0; i < 60; ++i)
53 printf("*");
54 printf("\n");
55
56 for (int j = 0; j < 5; ++j)
57 {
58 for (int i = 0; i < 20; ++i)
59 printf(" ");
60 printf("*");
61 for (int i = 0; i < 58; ++i)
62 printf(" ");
63 printf("*\n");
64 }
65
66 for (int i = 0; i < 20; ++i)
67 printf(" ");
68 printf("*");
69 for (int i = 0; i < 15; ++i)
70 printf(" ");
71 printf("《 欢迎来到贪吃蛇的世界!》");
72 for (int i = 0; i < 16; ++i)
73 printf(" ");
74 printf("*\n");
75
76 for (int i = 0; i < 20; ++i)
77 printf(" ");
78 printf("*");
79 for (int i = 0; i < 15; ++i)
80 printf(" ");
81 printf("《 请按空格键开始游戏 》");
82 for (int i = 0; i < 16; ++i)
83 printf(" ");
84 printf("*\n");
85
86 for (int j = 0; j < 10; ++j)
87 {
88 for (int i = 0; i < 20; ++i)
89 printf(" ");
90 printf("*");
91 for (int i = 0; i < 58; ++i)
92 printf(" ");
93 printf("*\n");
94 }
95
96 for (int i = 0; i < 20; ++i)
97 printf(" ");
98 for (int i = 0; i < 60; ++i)
99 printf("*");
100 for (int i = 0; i < 8; ++i)
101 printf("\n");
102 }
103
104 void TestSpace() //按空格开始游戏
105 {
106 char c;
107 while ((c = getch()) != ' ') //getch()在头文件<conio>内
108 {
109
110 }
111 system("cls"); //清屏
112 }
113
114 void ShowBackground() //展示游戏背景
115 {
116 for (int i = 0; i < 20; ++i)
117 printf(g_arrBackGround[i]);
118 }
119
120 void SetSnakeRandPos() //设置蛇的初始位置,默认蛇的身子为三节,向左移动
121 {
122 int x, y;
123 srand((unsigned)time(NULL));
124 x = rand()% 20 + 1; //因为蛇的身子起始为三节,所以x的范围为1-20(蛇不能起始就撞墙)
125 y = rand()% 18 + 1;
126
127 g_arrSnake[0][0] = y; //行 注意:x,y和初始背景中的行列刚好是反的
128 g_arrSnake[0][1] = x * 2; //列 注意:一个█占两个字节,所以算其坐标时要乘以2
129 g_arrSnake[0][2] = LEFT; //方向
130
131 g_arrSnake[1][0] = y;
132 g_arrSnake[1][1] = x * 2 + 2;
133 g_arrSnake[1][2] = LEFT;
134
135 g_arrSnake[2][0] = y;
136 g_arrSnake[2][1] = x * 2 + 4;
137 g_arrSnake[2][2] = LEFT;
138
139 DrawSnake();
140 }
141
142 void DrawSnake() //展示蛇
143 {
144 //因为一个█占两个字节,所以不能直接用strcpy(&arrBackGround[arrSnake[i][0]][arrSnake[i][1]],"█");否则会把\0拷贝进来,导致出错
145 //由于前面把arrSnake的所有元素都置为了0,所以当arrSnake[i][0]为0时,代表那个坐标处没有蛇的身子
146 for (int i = 0; g_arrSnake[i][0] != 0; ++i)
147 strncpy(&g_arrBackGround[g_arrSnake[i][0]][g_arrSnake[i][1]], "█", 2); //注意取地址符&不能漏掉!
148 }
149
150
151 void DestroySnake() //销毁蛇
152 {
153 for (int i = 0; g_arrSnake[i][0] != 0; ++i)
154 strncpy(&g_arrBackGround[g_arrSnake[i][0]][g_arrSnake[i][1]], " ", 2); //注意取地址符&不能漏掉!
155
156 }
157
158 void SnakeMove() //蛇动
159 {
160 DestroySnake();
161 for(int i = SNAKE_LENGTH - 1; i >= 1; --i)
162 {
163 if(g_arrSnake[i][0] != 0)
164 {
165 //把前一个节点的值,赋给当前节点
166 g_arrSnake[i][0] = g_arrSnake[i-1][0];
167 g_arrSnake[i][1] = g_arrSnake[i-1][1];
168 g_arrSnake[i][2] = g_arrSnake[i-1][2];
169 }
170 }
171
172 g_arrSnake[0][2] = g_iSnakeDir; //设置蛇头方向
173
174 //处理第一个节点(蛇头)
175 if(g_arrSnake[0][2] == LEFT || g_arrSnake[0][2] == RIGHT) //左右移动,列加减2
176 {
177 g_arrSnake[0][1] += g_arrSnake[0][2];
178 }
179 else
180 {
181 g_arrSnake[0][0] += g_arrSnake[0][2]; //上下移动,行加减1
182 }
183
184 DrawSnake();
185
186 }
187
188 void ChangeDir() //改变方向
189 {
190 //不能用getchar(), 会回显,并且要按回车之后才会开始读取
191 //不能用getch(), 同步检测
192
193 //异步检测
194 if(GetAsyncKeyState('W'))
195 {
196 if (g_arrSnake[0][2] != DOWN) //蛇不能回头
197 g_iSnakeDir = UP;
198 }
199
200 if(GetAsyncKeyState('S'))
201 {
202 if (g_arrSnake[0][2] != UP)
203 g_iSnakeDir = DOWN;
204 }
205
206 if(GetAsyncKeyState('A'))
207 {
208 if (g_arrSnake[0][2] != RIGHT)
209 g_iSnakeDir = LEFT;
210 }
211
212 if(GetAsyncKeyState('D'))
213 {
214 if (g_arrSnake[0][2] != LEFT)
215 g_iSnakeDir = RIGHT;
216 }
217 }
218
219 bool IsSnakeDie() //蛇死亡判断(包括撞墙和吃自己,两种情况)
220 {
221 if(g_arrSnake[0][2] == LEFT || g_arrSnake[0][2] == RIGHT) //如果蛇左右移动,则判断蛇头的左右是否是"█",如果是,则判定为蛇死亡
222 {
223 if(!strncmp(&g_arrBackGround[g_arrSnake[0][0]][g_arrSnake[0][1]+g_arrSnake[0][2]], "█", 2)) //注意取地址符&不能漏掉!
224 return true;
225 }
226 else //如果蛇上下移动,则判断蛇头的上下是否是"█"
227 {
228 if(!strncmp(&g_arrBackGround[g_arrSnake[0][0]+g_arrSnake[0][2]][g_arrSnake[0][1]], "█", 2))
229 return true;
230 }
231 return false;
232 }
233
234 void ProduceFood() //随机位置产生食物
235 {
236 //判断是否产生新的食物
237 if(g_bIsProFood == false)
238 return;
239
240 bool bFlag = true;
241 srand((unsigned)time(NULL));
242
243 while(1) //产生合法的食物,即食物不与蛇的身子重合
244 {
245 g_iRow = rand()% 18 + 1; //行
246 g_iCol = rand()% 22 + 1;
247
248 for (int i = 0; g_arrSnake[i][0] != 0; i++) //遍历蛇
249 if (g_iRow == g_arrSnake[i][0] && g_iCol == g_arrSnake[i][1]) //如果在食物产生在蛇身上
250 {
251 bFlag = false;
252 break;
253 }
254
255 if(bFlag == true)
256 break;
257 }
258
259 strncpy(&g_arrBackGround[g_iRow][g_iCol*2], "★", 2);
260 g_bIsProFood = false;
261 }
262
263 void SnakeGrowUp() //蛇变长
264 {
265 if(g_iRow == g_arrSnake[0][0] && g_iCol*2 == g_arrSnake[0][1]) //注意:列要乘以2
266 {
267 if (UP == g_arrSnake[g_iSnakeLength][2])
268 {
269 g_arrSnake[g_iSnakeLength+1][0] = g_arrSnake[g_iSnakeLength][0]+1;
270 g_arrSnake[g_iSnakeLength+1][1] = g_arrSnake[g_iSnakeLength][0];
271 g_arrSnake[g_iSnakeLength+1][2] = g_arrSnake[g_iSnakeLength][2];
272 }
273 else if (DOWN == g_arrSnake[g_iSnakeLength][2])
274 {
275 g_arrSnake[g_iSnakeLength+1][0] = g_arrSnake[g_iSnakeLength][0]-1;
276 g_arrSnake[g_iSnakeLength+1][1] = g_arrSnake[g_iSnakeLength][0];
277 g_arrSnake[g_iSnakeLength+1][2] = g_arrSnake[g_iSnakeLength][2];
278 }
279 else if (LEFT == g_arrSnake[g_iSnakeLength][2])
280 {
281 g_arrSnake[g_iSnakeLength+1][0] = g_arrSnake[g_iSnakeLength][0];
282 g_arrSnake[g_iSnakeLength+1][1] = g_arrSnake[g_iSnakeLength][0]+2;
283 g_arrSnake[g_iSnakeLength+1][2] = g_arrSnake[g_iSnakeLength][2];
284 }
285 else if (RIGHT == g_arrSnake[g_iSnakeLength][2])
286 {
287 g_arrSnake[g_iSnakeLength+1][0] = g_arrSnake[g_iSnakeLength][0];
288 g_arrSnake[g_iSnakeLength+1][1] = g_arrSnake[g_iSnakeLength][0]-2;
289 g_arrSnake[g_iSnakeLength+1][2] = g_arrSnake[g_iSnakeLength][2];
290 }
291 g_iSnakeLength++;
292 g_bIsProFood = true;
293 g_iScore++;
294 }
295
296 }
297
298 void PrintScore() //打印分数
299 {
300 COORD rd;
301 //设置光标位置
302 rd.X = 59;
303 rd.Y = 10;
304 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd);
305 printf("分数");
306
307 rd.X = 60;
308 rd.Y = 11;
309 //设置光标位置
310 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd);
311 //打印
312 printf ("%d", g_iScore);
313 }
main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <conio.h>
4 #include <windows.h>
5 #include <time.h>
6 #include "GreedySnake.h"
7
8
9 int main()
10 {
11 FirstPage();
12 TestSpace();
13 system("cls");
14 SetSnakeRandPos();
15 ShowBackground();
16
17 while (1)
18 {
19 system("cls");
20 ProduceFood();
21 SnakeGrowUp();
22 ChangeDir();
23
24 if(IsSnakeDie())
25 {
26 printf("snake die!\n");
27 break;
28 }
29
30 SnakeMove();
31 ShowBackground();
32 PrintScore();
33
34 Sleep(500);
35 }
36 system("pause");
37 return 0;
38 }