C语言 —— 贪吃蛇
参考视频: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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南