c语言实现贪吃蛇

游戏分析:

——初期分析

  1. 蛇:考虑到每个蛇节点包含x,y坐标以及指向下一个节点的指针(坐标用c语言内置类型COORD,本质是一个由x和y坐标构成的结构体类型),用结构体类型来表示每一个蛇身节点;
  2. 坐标:c语言有内置的坐标结构体类型,包括x和y坐标,一个坐标对应一个字符的大小,一个方形x方向占两个字符,即两个x坐标,y方向占一个;
  3. 光标位置,用一个Pos函数来移动光标到指定位置完成打印输出;
  4. 生成小蛇;
  5. 随机出现食物:食物的出现不能超出坐标边界,使用srand和rand方法生成随机食物;在生成食物的时候注意由于一开始的x坐标出现在偶数上,所以rand得到的食物的x坐标也必须是偶数,否则蛇吃不到,y坐标没有限制;
  6. 蛇移动,寻找食物:程序的核心,每次蛇的移动都是在响应一个移动事件,在每两次移动事件之间加上时间延缓来使蛇的移动看起来自然。当然可以通过加速和减速功能来减小或者增加延缓时间。如果蛇吃到食物,把食物节点作为新的头节点,后面的节点位置不动。否则把食物作为头节点,后面的节点依次前移,末尾节点设为空并刷新。
  7. 碰墙,碰自己,用户返回,游戏结束。

——几大模块

一 ,初始化模块(init.h):

  功能分析:

      初始化欢迎界面:

                    初始化地图

                 初始化蛇身

  具体实现:

      初始化欢迎界面:定位好坐标并打印相关欢迎信息即可;

                 初始化地图:定位好坐标并依次打印出方块即可;

                初始化蛇身:先生成一个节点,再自左向右依次设置剩下的节点,最后遍历打印出节点(方块);

二:判断模块(judge.h):

    功能分析:

         判断是否碰墙

                         判断是否碰到自己

                         判断游戏是否结束(通过标志位)

     具体实现:

        判断是否碰墙:如果蛇头坐标超出地图范围,判定为撞墙,修改游戏结束标志位;

        判断是否碰到自己:从头部开始遍历蛇,如果哪个节点坐标和头部节点坐标重合,就判断撞到自己;

        判断游戏是否结束(通过标志位):根据标志位的状态判断游戏是否结束;

三:游戏模块(snake.cpp):

            功能分析:

        随机出现食物

                         玩家操作蛇移动,每次响应一个输入事件

                         游戏结束

            具体实现:

        随机出现食物:每次通过rand函数生成一个随机坐标,把x转化为偶数坐标,y不变,然后把光标移动到对应位置打印出食物;

        玩家操作蛇移动,每次响应一个键盘输入事件:游戏核心,每次响应移动事件后判断是否吃到食物:

        1. 吃到食物:把食物节点作为新的头节点,其余节点位置不变,游戏分数加point;
        2. 没吃到食物,把新开的后继节点作为新的头节点,剩余节点依次向前移动;这样原来的最后一个节点就成为了空节点,打印出空格来覆盖原来的方块。

        游戏结束:结束游戏。

     

代码如下:

  1 // 定义蛇身节点
  2 typedef struct SNAKE{
  3     int x;
  4     int y;
  5     struct SNAKE*next;
  6 }snake;
  7 snake *head;    //头指针
  8 //设置光标位置
  9 void Pos(int x, int y)
 10 {
 11     //坐标类型结构体
 12     COORD pos;
 13     pos.X = x;
 14     pos.Y = y;
 15     //定义并初始化句柄
 16     HANDLE Houtput = GetStdHandle(STD_OUTPUT_HANDLE);
 17     //设置光标位置
 18     SetConsoleCursorPosition(Houtput, pos);
 19 }
 20 
 21 void SetColor(int color_num) //需包含头文件windows.h
 22 {
 23     using namespace std;
 24     HANDLE color; //声明一个句柄
 25     color = GetStdHandle(STD_OUTPUT_HANDLE); //取得标准输出句柄
 26     SetConsoleTextAttribute(color, color_num);
 27     //设置颜色函数SetConsoleTextAttribute有两个参数,第一个为句柄,第二个为颜色代表值 
 28     //可以使用「|」在第二个参数所填颜色间隔开,实现混色
 29 }
 30 
 31 //欢迎界面
 32 void welcomepage()
 33 {
 34     Pos(40, 12);
 35     SetColor(6);
 36     printf("~~欢迎来到贪吃蛇游戏~~");
 37     Pos(40, 25);
 38     printf("用↑,↓,←,→控制蛇的移动\n");
 39     system("pause");
 40     system("cls");
 41 }
 42 //初始化地图58/2=29列26行
 43 void Map_create()
 44 {
 45     int i;
 46     //■占两个字符的位置(光标移动一位对应一个字符,两个字符光标每次移动两位,也就是坐标值每次加2,一个坐标值对应一个字符位)
 47     //上下 
 48     for (i = 0; i < 58; i += 2)
 49     {
 50         //移动光标
 51         Pos(i, 0);
 52         SetColor(4);
 53         printf("");
 54         Pos(i, 26);
 55         SetColor(6);
 56         printf("");
 57     }
 58     //左右    y取1,2,3...25
 59     for (i = 0; i < 26; i++)
 60     {
 61         //移动光标
 62         Pos(0, i);
 63         SetColor(4);
 64         printf("");
 65         Pos(56, i);
 66         SetColor(6);
 67         printf("");
 68     }
 69     printf("\n");
 70 }
 71 
 72 //初始化蛇身,x,y坐标的取值范围57和25
 73 void Snakeinit()
 74 {
 75     snake *tail;    //尾指针
 76     int i;
 77     tail = (snake*)malloc(sizeof(snake));    //初始化尾指针,采用头插法
 78     tail->x = 24;    //这个设定注定头节点的x坐标只能是偶数
 79     tail->y = 5;    //y坐标任意
 80     tail->next = NULL;
 81     //生成五节长的小蛇
 82     for (i = 1; i <= 4; i++)
 83     {
 84         //生成头指针,每次将头指针赋值给尾指针,使蛇增加一节,前面的节已经链在了链表中
 85         head = (snake*)malloc(sizeof(snake));
 86         head->next = tail;
 87         head->x = 24 + 2 * i;
 88         head->y = 5;
 89         tail = head;
 90     }
 91     //从头部开始打印小蛇
 92     while (tail != NULL)
 93     {
 94         //修改光标
 95         Pos(tail->x, tail->y);
 96         SetColor(2);
 97         printf("");
 98         tail = tail->next;
 99     }
100 
101 
102 }
init.h
 1 int gameoverflag = 0; //游戏分三种情况,1:撞到墙;2:咬到自己;3:主动退出游戏。
 2 int score = 0, point = 10;//总得分与每次吃食物得分。
 3 
 4 int biteself()//判断是否咬到了自己
 5 {
 6     snake *self;
 7     self = head->next;
 8     while (self != NULL)
 9     {
10         if (self->x == head->x && self->y == head->y)
11         {
12             return 1;
13         }
14         self = self->next;
15     }
16     return 0;
17 }
18 
19 
20 void endgame()//结束游戏
21 {
22 
23     system("cls");
24     Pos(24, 12);
25     if (gameoverflag== 1)
26     {
27         printf("对不起,您撞到墙了。游戏结束.");
28     }
29     else if (gameoverflag == 2)
30     {
31         printf("对不起,您咬到自己了。游戏结束.");
32     }
33     else if (gameoverflag== 3)
34     {
35         printf("您的已经结束了游戏。");
36     }
37     Pos(24, 13);
38     printf("您的得分是%d\n", score);
39     exit(0);
40 }
41 
42 
43 void cantcrosswall()//不能穿墙
44 {
45     if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
46     {
47         gameoverflag = 1;
48         endgame();
49     }
50 }
51 
52 void game_pause()//暂停
53 {
54     while (1)
55     {
56         Sleep(300);
57         if (GetAsyncKeyState(VK_SPACE))
58         {
59             break;
60         }
61 
62     }
63 }
judge.h
  1 #include<stdio.h>
  2 #include<time.h>
  3 #include<windows.h>
  4 #include<stdlib.h>
  5 #include "init.h"
  6 #include "judge.h"
  7 
  8 #define U 1
  9 #define D 2
 10 #define L 3 
 11 #define R 4 //蛇的状态,U:上 ;D:下;L:左 R:右
 12 
 13 
 14 
 15 //全局变量//
 16 int status, sleeptime = 200;//蛇每次移动的时间间隔200ms
 17 snake *food;//食物指针
 18 snake *q;//遍历蛇的时候用到的指针
 19 
 20 
 21 
 22 void createfood()//随机出现食物
 23 {
 24     snake *food_1;
 25     srand((unsigned)time(NULL));
 26     //初始化x坐标
 27     food_1 = (snake*)malloc(sizeof(snake));
 28     while ((food_1->x % 2) != 0) //保证其为偶数,使得食物能与蛇头对其
 29     {
 30         food_1->x = rand() % 52 + 2;
 31     }
 32     food_1->y = rand() % 24 + 1;
 33     q = head;
 34     while (q->next == NULL)
 35     {
 36         if (q->x == food_1->x && q->y == food_1->y) //判断蛇身是否与食物重合
 37         {
 38             free(food_1);
 39             createfood();
 40         }
 41         q = q->next;
 42     }
 43     Pos(food_1->x, food_1->y);
 44     food = food_1;
 45     SetColor(4);
 46     printf("");
 47 }
 48 
 49 
 50 
 51 void snakemove()//蛇前进,上U,下D,左L,右R
 52 {
 53     snake * nexthead;
 54     cantcrosswall();
 55 
 56     nexthead = (snake*)malloc(sizeof(snake));
 57     if (status == U)
 58     {
 59         nexthead->x = head->x;
 60         nexthead->y = head->y - 1;
 61         if (nexthead->x == food->x && nexthead->y == food->y)//如果下一个有食物//
 62         {
 63             nexthead->next = head;
 64             head = nexthead;
 65             q = head;
 66             while (q != NULL)
 67             {
 68                 Pos(q->x, q->y);
 69                 SetColor(6);
 70                 printf("");
 71                 q = q->next;
 72             }
 73             score = score + point;
 74             createfood();
 75         }
 76         else //如果没有食物//
 77         {
 78             nexthead->next = head;
 79             head = nexthead;
 80             q = head;
 81             while (q->next->next != NULL)
 82             {
 83                 Pos(q->x, q->y);
 84                 SetColor(9);
 85                 printf("");
 86                 q = q->next;
 87             }
 88             Pos(q->next->x, q->next->y);
 89             printf(" ");
 90             free(q->next);
 91             q->next = NULL;
 92         }
 93     }
 94     if (status == D)
 95     {
 96         nexthead->x = head->x;
 97         nexthead->y = head->y + 1;
 98         if (nexthead->x == food->x && nexthead->y == food->y) //有食物
 99         {
100             nexthead->next = head;
101             head = nexthead;
102             q = head;
103             while (q != NULL)
104             {
105                 Pos(q->x, q->y);
106                 SetColor(6);
107                 printf("");
108                 q = q->next;
109             }
110             score = score + point;
111             createfood();
112         }
113         else //没有食物
114         {
115             nexthead->next = head;
116             head = nexthead;
117             q = head;
118             while (q->next->next != NULL)
119             {
120                 Pos(q->x, q->y);
121                 SetColor(12);
122                 printf("");
123                 q = q->next;
124             }
125             Pos(q->next->x, q->next->y);
126             printf(" ");
127             free(q->next);
128             q->next = NULL;
129         }
130     }
131     if (status == L)
132     {
133         nexthead->x = head->x - 2;
134         nexthead->y = head->y;
135         if (nexthead->x == food->x && nexthead->y == food->y)//有食物
136         {
137             nexthead->next = head;
138             head = nexthead;
139             q = head;
140             while (q != NULL)
141             {
142                 Pos(q->x, q->y);
143                 SetColor(6);
144                 printf("");
145                 q = q->next;
146             }
147             score = score + point;
148             createfood();
149         }
150         else //没有食物
151         {
152             nexthead->next = head;
153             head = nexthead;
154             q = head;
155             while (q->next->next != NULL)
156             {
157                 Pos(q->x, q->y);
158                 SetColor(14);
159                 printf("");
160                 q = q->next;
161             }
162             Pos(q->next->x, q->next->y);
163             printf(" ");
164             free(q->next);
165             q->next = NULL;
166         }
167     }
168     if (status == R)
169     {
170         nexthead->x = head->x + 2;
171         nexthead->y = head->y;
172         if (nexthead->x == food->x && nexthead->y == food->y)//有食物
173         {
174             nexthead->next = head;
175             head = nexthead;
176             q = head;
177             while (q != NULL)
178             {
179                 Pos(q->x, q->y);
180                 SetColor(6);
181                 printf("");
182                 q = q->next;
183             }
184             score = score + point;
185             createfood();
186         }
187         else //没有食物
188         {
189             nexthead->next = head;
190             head = nexthead;
191             q = head;
192             while (q->next->next != NULL)
193             {
194                 Pos(q->x, q->y);
195                 SetColor(6);
196                 printf("");
197                 q = q->next;
198             }
199             Pos(q->next->x, q->next->y);
200             printf(" ");
201             free(q->next);
202             q->next = NULL;
203         }
204     }
205     if (biteself() == 1) //判断是否会咬到自己
206     {
207         gameoverflag = 2;
208         endgame();
209     }
210 }
211 
212 
213 //玩游戏
214 void gameplay()
215 {
216 
217     Pos(64, 15);
218     SetColor(6);
219     printf("不能穿墙,不能咬到自己\n");
220     Pos(64, 16);
221     SetColor(7);
222     printf("用↑.↓.←.→分别控制蛇的移动.");
223     Pos(64, 17);
224     SetColor(8);
225     printf("F1 为加速,F2 为减速\n");
226     Pos(64, 18);
227     SetColor(9);
228     printf("ESC :退出游戏.space:暂停游戏.");
229     Pos(64, 20);
230     SetColor(10);
231     printf("~~**~~");
232     status = R;
233     while (1)
234     {
235         Pos(64, 10);
236         printf("得分:%d ", score);
237         Pos(64, 11);
238         printf("每个食物得分:%d分", point);
239         if (GetAsyncKeyState(VK_UP) && status != D)
240         {
241             status = U;
242         }
243         else if (GetAsyncKeyState(VK_DOWN) && status != U)
244         {
245             status = D;
246         }
247         else if (GetAsyncKeyState(VK_LEFT) && status != R)
248         {
249             status = L;
250         }
251         else if (GetAsyncKeyState(VK_RIGHT) && status != L)
252         {
253             status = R;
254         }
255         else if (GetAsyncKeyState(VK_SPACE))
256         {
257             game_pause();
258         }
259         else if (GetAsyncKeyState(VK_ESCAPE))
260         {
261             gameoverflag = 3;
262             endgame();
263         }
264         //加速,就是缩小两次移动事件之间的响应速度(反应时间)
265         else if (GetAsyncKeyState(VK_F1))
266         {
267             if (sleeptime >= 50)
268             {
269                 //每次减去30ms
270                 sleeptime = sleeptime - 30;
271                 //加速奖励分,以后吃到食物多加分
272                 point = point + 2;
273             }
274         }
275         //减速,就是增加两次移动事件之间的响应速度(反应时间)
276         else if (GetAsyncKeyState(VK_F2))
277         {
278             if (sleeptime<350)
279             {
280                 sleeptime = sleeptime + 30;
281                 //减速难度下降,以后吃到食物分减少
282                 point= point- 2;
283                 if (sleeptime == 350)
284                 {
285                     point= 1; //保证最低分为1
286                 }
287             }
288         }
289         //刷新事件,两次事件之间间隔sleeptime的毫秒
290         Sleep(sleeptime);
291         snakemove();
292     }
293 }
294 
295 
296 
297 void game_init()//游戏初始化
298 {
299     system("mode con cols=100 lines=30");
300     welcomepage();
301     Map_create();
302     Snakeinit();
303     createfood();
304 }
305 
306 int main()
307 {
308     //初始化游戏
309     game_init();
310     //开始玩游戏
311     gameplay();
312     return 0;
313 }
snack.cpp

Ps:我用了字体颜色变换函数皮了一下,不喜欢的可以去掉这个功能。

猜你喜欢

转载自www.cnblogs.com/lh2018/p/9221050.html