贪吃蛇小游戏-----C语言实现


1.分析

  众所周知,贪吃蛇游戏是一款经典的益智游戏,有PC和手机等多平台版本,既简单又耐玩。该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,蛇不能撞墙,也不能装到自己,否则游戏结束。玩过贪吃蛇的朋友都知道这个小游戏有一圈“墙”、还有食物以及蛇,还有吃了食物之后的分数。所以通过C语言实现贪吃蛇,可以分为以下几个模块来实现:

  a)编程实现“墙”

  b)实现随机食物的生成

  c)蛇的构建

  d)以上三部分都实现了之后,实现游戏运行的部分,包括蛇的移动、吃食物、判断是否撞墙或者撞到自己。

  e)游戏结束时的相关操作

2.具体思路

  要通过C语言实现贪吃蛇,首先就要用C语言将贪吃蛇的相关信息描述出来。C语言提供了结构体类型,我们可以用结构体描述蛇的结点(结点的横纵坐标)、运动状态、总分数、每个食物的分数等等。

  首先实现进入游戏的"welcome"界面,为了将“欢迎来到贪吃蛇游戏”打印到屏幕的中间,可以运用库函数先设置窗口的大小(system("mode con cols=100 lines=30");将窗口设置为长100,宽30),再通过库函数中的GetStdHandle函数、SetConsoleCursorPosition函数(把光标定位到我们需要的位置)将这句话打印到屏幕中央。

  其次可以通过相同的方法将光标固定到我们需要的位置,用特殊字符‘■’打印实现墙(注意,‘■’在c中占用两个字符,所以在设置循环条件时要格外注意)

  接着通过编程实现蛇的移动,本文中蛇是通过单链表实现的,因此在实现蛇的移动时,如果蛇接下来走的位置(上下左右)为食物,将这个位置的用指针表示,可以将食物头插到用_psnake指针维护的蛇身中,如果接下来的位置不是食物,同样头插到蛇身中,再将蛇的最后一个结点打印时输出为空格字符,然后free最后一个节点。

3.代码如下

snake.h:

 1 #pragma once
 2 
 3 #include<Windows.h>
 4 #include<stdio.h>
 5 #include<time.h>
 6 #include<stdlib.h>
 7 
 8 #define WALL "■"
 9 #define FOOD "●"
10 
11 #define INIT_X 20
12 #define INIT_Y 18
13 typedef struct SnakeNode 14 { 15     int x; 16     int y; 17     struct SnakeNode *next; 18 }SnakeNode, *pSnakeNode; 19 
20 //蛇的方向
21 enum Diretion 22 { 23  UP, 24  DOWN, 25  LEFT, 26  RIGHT 27 }; 28 
29 //状态
30 enum GameState 31 { 32  OK, 33  NORMAL_END, 34  KILL_BY_WALL, 35  KILL_BY_SELF 36 }; 37 //游戏结构体
38 typedef struct Snake 39 { 40     pSnakeNode _psnake;//维护蛇身的指针
41     pSnakeNode _pFood;//维护食物的位置
42     int _TotalScore;//总分数
43     int _AddScore;//增加的分数
44     int _SleepTime;//休眠时间
45     enum Direction _Dir; 46     enum GameStatus _Status; 47 }Snake, *pSnake; 48 
49 void GameStart(pSnake ps); 50 void WelcomeToGame();//欢迎界面函数
51 void SetPos(int x, int y); 52 void CreateMap();//创建地图
53 void InitSnake(pSnake ps); 54 void CreateFood(pSnake ps);//创建食物
55 void GameRun(pSnake ps);//运行游戏
56 void pause();//暂停函数
57 
58 void snakmove(pSnake ps); 59 int NextHasFood(pSnakeNode pn, pSnakeNode pf);//判断下个结点是否为食物
60 void EatFood(pSnake ps,pSnakeNode pn);//吃食物
61 void NoFood(pSnake ps, pSnakeNode pn);//没有食物
62 void KillBYWALL(pSnake ps); 63 void KillBySelf(pSnake ps); 64 void GameEnd(pSnake ps);

snake.c:

 1 #include"snake.h"
 2 void  SetPos(int x, int y)  3 {  4     COORD pos = { 0 };  5     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  6     pos.X = x; pos.Y = y;  7     SetConsoleCursorPosition(handle, pos);//把光标定位到我们需要的位置了
 8 }  9 void WelcomeToGame()//欢迎界面函数
 10 {  11     //设置窗口大小
 12     system("mode con cols=100 lines=30");  13     SetPos(40, 13);//分装的函数用来定位光标
 14     printf("欢迎来到贪吃蛇小游戏\n");  15     SetPos(35, 25);  16     system("pause");//暂停
 17     system("cls");//清空屏幕
 18     SetPos(30, 9);  19     printf("用↑,↓,←,→来控制蛇的移动,F1为加速,F2为减速\n");  20     SetPos(40, 11);  21     printf("加速获得分数更多\n");  22     SetPos(35, 25);  23     system("pause");  24     system("cls");  25 }  26 
 27 void CreateMap()  28 {  29     int i = 0;  30     //
 31     for (i = 0; i <= 58; i += 2)  32  {  33         SetPos(i, 0);  34  printf(WALL);  35  }  36     //
 37     for (i = 0; i <= 58; i += 2)  38  {  39         SetPos(i, 27);  40  printf(WALL);  41  }  42     //
 43     for (i = 1; i <= 26; i++)  44  {  45         SetPos(0, i);  46  printf(WALL);  47  }  48     //
 49     for (i = 1; i <= 26; i++)  50  {  51         SetPos(58, i);  52  printf(WALL);  53  }  54 }  55 pSnakeNode BuyNode()  56 {  57     pSnakeNode pRet = (pSnakeNode)malloc(sizeof(SnakeNode));  58     if (pRet == NULL)  59  {  60         perror("BuyNode::malloc()");  61  exit(EXIT_FAILURE);  62  }  63     pRet->x = 0;  64     pRet->y = 0;  65     pRet->next = NULL;  66     return pRet;  67 }  68 void InitSnake(pSnake ps)  69 {  70     pSnakeNode first = BuyNode();//创建蛇头
 71     pSnakeNode cur = NULL;  72     first->x = INIT_X;  73     first->y = INIT_Y;  74     int i = 0;  75     for (i = 1; i <= 4; i++)  76  {  77         cur = BuyNode();//创建蛇身
 78         cur->x = first->x + 2;  79         cur->y = first->y;  80         cur->next = first;  81         first = cur;  82  }  83     //打印蛇
 84     while (cur)  85  {  86         SetPos(cur->x, cur->y);  87  printf(FOOD);  88         cur = cur->next;  89  }  90     ps->_psnake = first;  91 }  92 
 93 void CreateFood(pSnake ps)  94 {  95     pSnakeNode pfood = BuyNode();  96     pSnakeNode cur = ps->_psnake;  97     pfood->y = rand() % 26 + 1;  98     do
 99  { 100         pfood->x = rand() % 55 + 2;//0-54,+2产生2-56
101     } while (pfood->x % 2 != 0); 102     while (cur) 103  { 104         if (cur->x == pfood->x&&cur->y == pfood->y) 105  { 106  CreateFood(ps); 107  } 108         cur = cur->next; 109  } 110     ps->_pFood = pfood; 111     SetPos(pfood->x, pfood->y); 112  printf(FOOD); 113 } 114 
115 void GameStart(pSnake ps) 116 { 117     //打印欢迎界面
118  WelcomeToGame(); 119     //创建地图,画墙
120  CreateMap(); 121     //初始化蛇
122  InitSnake(ps); 123     //初始化食物
124  CreateFood(ps); 125     //游戏运行
126     ps->_AddScore = 10;//每次增加的分数
127     ps->_TotalScore = 0;//总分
128     ps->_Dir = RIGHT;//方向
129     ps->_SleepTime = 200;//0.2秒
130     ps->_Status = OK;//状态
131 } 132 
133 void pause()//暂停函数
134 { 135     while (1) 136  { 137         Sleep(100); 138         if (GetAsyncKeyState(VK_SPACE)) 139  { 140             return; 141  } 142  } 143 } 144 
145 int NextHasFood(pSnakeNode pn, pSnakeNode pf) 146 { 147     return (pn->x == pf->x) && (pn->y == pf->y); 148 } 149 
150 void EatFood(pSnake ps, pSnakeNode pn)//吃食物
151 { 152     pSnakeNode cur = NULL; 153     pn->next = ps->_psnake;//头插
154     ps->_psnake = pn; 155     cur = ps->_psnake; 156     ps->_TotalScore += ps->_AddScore; 157     while (cur) 158  { 159         SetPos(cur->x, cur->y); 160  printf(FOOD); 161         cur = cur->next; 162  } 163  CreateFood(ps); 164 } 165 
166 void NoFood(pSnake ps, pSnakeNode pn)//没有食物
167 { 168     pSnakeNode cur = NULL; 169     pn->next = ps->_psnake;//头插
170     ps->_psnake = pn; 171     cur = ps->_psnake; 172     while (cur->next->next) 173  { 174         SetPos(cur->x, cur->y); 175  printf(FOOD); 176         cur = cur->next; 177  } 178     SetPos(cur->x, cur->y); 179  printf(FOOD); 180     SetPos(cur->next->x, cur->next->y); 181     printf(" "); 182     free(cur->next); 183     cur->next = NULL; 184 } 185 
186 void snakmove(pSnake ps)//蛇的移动
187 { 188     pSnakeNode pNextNode = BuyNode(); 189     SetPos(65, 8); 190     printf("总分:%d", ps->_TotalScore); 191     SetPos(65, 9); 192     printf("每个食物的得分:%d ", ps->_AddScore); 193     //
194     switch (ps->_Dir) 195  { 196         case UP: 197  { 198             pNextNode->x = ps->_psnake->x; 199             pNextNode->y = ps->_psnake->y - 1; 200             if (NextHasFood(pNextNode,ps->_pFood)) 201  { 202                 //下一个节点是食物
203  EatFood(ps,pNextNode); 204  } 205             else
206  { 207  NoFood(ps,pNextNode); 208  } 209             break; 210  } 211         case DOWN: 212  { 213             pNextNode->x = ps->_psnake->x; 214             pNextNode->y = ps->_psnake->y + 1; 215             if (NextHasFood(pNextNode, ps->_pFood)) 216  { 217               //下一个节点是食物
218  EatFood(ps, pNextNode); 219  } 220             else
221  { 222  NoFood(ps, pNextNode); 223  } 224             break; 225  } 226         case LEFT: 227  { 228             pNextNode->x = ps->_psnake->x-2; 229             pNextNode->y = ps->_psnake->y; 230             if (NextHasFood(pNextNode, ps->_pFood)) 231  { 232                 //下一个节点是食物
233  EatFood(ps, pNextNode); 234  } 235             else
236  { 237  NoFood(ps, pNextNode); 238  } 239             break; 240  } 241         case RIGHT: 242  { 243             pNextNode->x = ps->_psnake->x+2; 244             pNextNode->y = ps->_psnake->y ; 245             if (NextHasFood(pNextNode, ps->_pFood)) 246  { 247                  //下一个节点是食物
248  EatFood(ps, pNextNode); 249  } 250             else
251  { 252  NoFood(ps, pNextNode); 253  } 254             break; 255  } 256         default: 257  { 258             break; 259  } 260  } 261 } 262 
263 void KillBYWALL(pSnake ps) 264 { 265     if ((ps->_psnake->x == 0) ||
266         (ps->_psnake->x == 58) || 
267         (ps->_psnake->y == 0) ||
268         (ps->_psnake->y == 27)) 269  { 270         ps->_Status = KILL_BY_WALL; 271  } 272 } 273 
274 void KillBySelf(pSnake ps) 275 { 276     pSnakeNode tnext = ps->_psnake->next; 277     while (tnext) 278  { 279         if ((tnext->x == ps->_psnake->x) && (tnext->y == ps->_psnake->y)) 280  { 281             ps->_Status = KILL_BY_SELF; 282             return; 283  } 284         tnext = tnext->next; 285  } 286 
287 } 288 void PrintHelpInfo() 289 { 290     SetPos(65, 11); 291     printf("用↑,↓,←,→来控制蛇的移动"); 292     SetPos(65, 12); 293     printf("F1为加速,F2为减速\n"); 294     SetPos(65, 13); 295     printf("加速获得分数更多\n"); 296     SetPos(65, 14); 297     printf("按空格暂停游戏\n"); 298 
299 } 300 
301 void GameEnd(pSnake ps) 302 { 303     pSnakeNode cur = ps->_psnake; 304     SetPos(25, 14); 305     if (ps->_Status == NORMAL_END) 306  { 307         SetPos(70, 20); 308         printf("游戏正常接结束\n"); 309         SetPos(70, 21); 310  } 311     else if (ps->_Status == KILL_BY_SELF) 312  { 313         SetPos(70, 20); 314         printf("蛇撞到自己了\n"); 315         SetPos(70, 21); 316  } 317     else if (ps->_Status == KILL_BY_WALL) 318  { 319         SetPos(70, 20); 320         printf("撞到墙了\n"); 321         SetPos(70, 21); 322  } 323     while (cur) 324  { 325         pSnakeNode del = cur; 326         cur = cur->next; 327         free(del); 328         del = NULL; 329  } 330     ps->_psnake = NULL; 331     free(ps->_pFood); 332     ps->_pFood = NULL; 333 } 334 
335 void GameRun(pSnake ps) 336 { 337  PrintHelpInfo(); 338     do
339  { 340         //确定方向
341         if (GetAsyncKeyState(VK_UP)&&(ps->_Dir!=DOWN)) 342  { 343             ps->_Dir = UP; 344  } 345         else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP) 346  { 347             ps->_Dir = DOWN; 348  } 349         else if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT) 350  { 351             ps->_Dir = LEFT; 352  } 353         else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT) 354  { 355             ps->_Dir = RIGHT; 356  } 357         else if (GetAsyncKeyState(VK_SPACE)) 358  { 359             //暂停游戏
360  pause(); 361  } 362         else if (GetAsyncKeyState(VK_ESCAPE)) 363  { 364             //结束游戏
365             ps->_Status = NORMAL_END; 366             break; 367  } 368         else if (GetAsyncKeyState(VK_F1)) 369  { 370             //加速
371             if (ps->_SleepTime >= 40) 372  { 373                 ps->_SleepTime -= 20; 374                 ps->_AddScore += 2; 375  } 376  } 377         else if (GetAsyncKeyState(VK_F2)) 378  { 379             //减速
380             if (ps->_SleepTime <= 300) 381  { 382                 ps->_SleepTime += 20; 383                 ps->_AddScore -= 2; 384  } 385             if (ps->_SleepTime > 300) 386  { 387                 ps->_AddScore = 1;//不能一直减
388  } 389  } 390         Sleep(ps->_SleepTime);//睡眠 391         //蛇的移动
392  snakmove(ps); 393  KillBYWALL(ps); 394  KillBySelf(ps); 395     } while (ps->_Status == OK); 396 }

 

test.c:

 1 #include"snake.h"
 2 
 3 void test()  4 {  5  srand((unsigned)time(NULL));  6     Snake snake = { 0 };//创建贪吃蛇
 7     GameStart(&snake);  8     GameRun(&snake);  9     GameEnd(&snake); 10 } 11 
12 int main() 13 { 14  test(); 15     system("pause"); 16     return 0; 17 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM