貪吃蛇小游戲-----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