利用C/C++实现贪吃蛇
(注意:本文章仅供参考,第一次写博客还请多多指教。理解本文章需要easyx和c++等基础知识,并且需要了解贪吃蛇游戏机制)
贪吃蛇机制介绍
相信绝大多数人都曾玩过或者了解过贪吃蛇这款经典的游戏。贪吃蛇顾名思义,就是让蛇尽可能的吃食物。玩家可通过方向键或自定义键来控制蛇头的方向,使它吃到地图出现的随机食物。蛇每吃到一个食物,自身便会增长。当蛇碰到地图的边界或是蛇碰到自身,蛇便会死亡,游戏便结束。
机制大概了解过后,我们将考虑如何实现这类游戏。
设计与分析
首先,我们分析游戏整体结构大概由四个部分构成——界面、地图、蛇、食物。
1、界面:界面能够方便玩家的使用,可让玩家自行选择游戏的开始或结束;通过界面,我们可以设定一些有趣的东西来增加玩家的游戏体验,例如:让玩家选择蛇的速度,以灵活调节游戏难度。
2、地图:地图能为蛇提供活动空间,同时也是蛇位置的坐标轴,方便定位。
3、蛇:蛇是游戏的灵魂。蛇可以定义如下属性:坐标、方向、速度、长度。蛇。蛇的行为有:移动、吃食物、死亡。
4、食物:食物在地图中随机分布,具有坐标(可以尝试去增加颜色属性、大小属性,本文章由于篇幅有限,暂不提供)。
思维导图如下
首先设计用户界面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37//部分函数可以暂时不用考虑 void menu() { initgraph(640, 480); int flag = 1; while (flag) { cleardevice(); outtextxy(280, 180, "贪吃蛇游戏"); outtextxy(280, 200, "按1开始游戏"); outtextxy(280, 220, "按2结束游戏"); //接受输入指令0、1 char ch = _getch(); switch (ch) { //开始 case '1': { food F; Initfood(F);//食物初始化 Snake S; hatch(S);//蛇初始化 control_speed(S.speed);//蛇速度控制函数 drawsnake(S, F);//开始绘制游戏面板 break; } //结束 case '2': flag = 0; break; default : break; } } closegraph(); }
接下来可以通过结构体来定义蛇和食物
1
2
3
4
5
6
7
8
9
10
11typedef struct Snake { int speed = 0;//速度 pair<int, int> coor[MAXSIZE]={};//坐标(x, y) int dir;//方向 int length;//长度 }; typedef struct food { pair<int, int> place[MAXSIZE] = {};//坐标 int score;//分数 };
接下来将食物和蛇进行初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void Initfood(food& F) { F.score = 0; srand(time(NULL)); //将食物坐标随机设置 for (int i = 0; i < 100; i++) { F.place[i].first = rand() % (640 - R) + R; F.place[i].second = rand() % (480 - R) + R; } } void hatch(Snake &S) { S.length = 3; S.dir = 2; S.speed = 0; //先给出3节身体 for (int i = 0; i < 3; i++) { S.coor[i].first = 40 - i * 10; S.coor[i].second = 30; } }
再接着设计蛇速度控制函数
1
2
3
4
5
6
7void control_speed(int &speed) { cleardevice(); outtextxy(280, 180, "请选择蛇的速度1-5"); char ch = _getch(); speed = ch - '0'; }
最关键的蛇运动机制设计来了,我将分段讲解
1、绘制蛇(蛇将有一系列正方体块组成)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; //蛇头设为绿色,方便区分 if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); }
2、绘制食物(食物由单个正方体组成)
1
2
3
4int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R);
3、蛇的运动
像人的运动是通过脚向前迈步来制动整个躯干一样,蛇头同样驱动整个身体。也就是说我们只要控制蛇头的运动方向及前进,躯干便会跟着蛇头一起移动。蛇躯干的每个节点只需要继承上一个节点的位置即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26void movesnake(Snake& S) { //继承坐标 for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } }
4、蛇运动控制
使用方向键改变蛇头的运动方向即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': //这里用if主要是因为蛇运动的机制:当蛇在一某方向运动的途中,不能直接往反方向运动(这样会导致蛇身体重叠),只能通过以当前运动方向为正方向,进行左右移动来改变方向。 if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } }
4、吃食物
吃完食物的结果:出现下一个食物、蛇变长
1
2
3
4
5
6
7
8
9void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } }
5、判断是否死亡
死亡判断有两种结果:1、碰壁。2、自身形成回路(自己咬自己)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } }
蛇的运动机制设计基本大功告成,可以自行在地图上进行修饰,像加入分数栏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } } void movesnake(Snake& S) { for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } } int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } } void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } } void drawsnake(Snake& S, food F) { char out[3] = {}; BeginBatchDraw(); while (1) { cleardevice(); for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); } } int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R); sprintf_s(out, "%d", F.score * S.speed); setbkmode(0); outtextxy(570, 20, "得分"); outtextxy(620, 20, out); FlushBatchDraw(); Sleep(200-S.speed*30); while(_kbhit()) { control_dir(S.dir); } movesnake(S); Eating(S, F); if (isdead(S)) break; } cleardevice(); sprintf_s(out, "%d", F.score * S.speed); outtextxy(280, 180, "得分"); outtextxy(320, 180, out); outtextxy(280, 200, "按Enter键继续"); FlushBatchDraw(); getchar(); EndBatchDraw(); }
完整代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237#include <iostream> #include <graphics.h> #include <conio.h> #include <time.h> using namespace std; #define MAXSIZE 100 #define R 5 typedef struct Snake { int speed = 0;//速度 pair<int, int> coor[MAXSIZE]={}; int dir = 2; int length = 3; }; typedef struct food { pair<int, int> place[MAXSIZE] = {}; int score; }; void Initfood(food& F) { F.score = 0; srand(time(NULL)); for (int i = 0; i < 100; i++) { F.place[i].first = rand() % (640 - R) + R; F.place[i].second = rand() % (480 - R) + R; } } void hatch(Snake &S) { S.length = 3; S.dir = 2; S.speed = 0; for (int i = 0; i < 3; i++) { S.coor[i].first = 40 - i * 10; S.coor[i].second = 30; } } void control_speed(int &speed) { cleardevice(); outtextxy(280, 180, "请选择蛇的速度1-5"); char ch = _getch(); speed = ch - '0'; } void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } } void movesnake(Snake& S) { for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } } int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } } void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } } void drawsnake(Snake& S, food F) { char out[3] = {}; BeginBatchDraw(); while (1) { cleardevice(); for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); } } int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R); sprintf_s(out, "%d", F.score * S.speed); setbkmode(0); outtextxy(570, 20, "得分"); outtextxy(620, 20, out); FlushBatchDraw(); Sleep(200-S.speed*30); while(_kbhit()) { control_dir(S.dir); } movesnake(S); Eating(S, F); if (isdead(S)) break; } cleardevice(); sprintf_s(out, "%d", F.score * S.speed); outtextxy(280, 180, "得分"); outtextxy(320, 180, out); outtextxy(280, 200, "按Enter键继续"); FlushBatchDraw(); getchar(); EndBatchDraw(); } void menu() { initgraph(640, 480); int flag = 1; while (flag) { cleardevice(); outtextxy(280, 180, "贪吃蛇游戏"); outtextxy(280, 200, "按1开始游戏"); outtextxy(280, 220, "按2结束游戏"); char ch = _getch(); switch (ch) { case '1': { food F; Initfood(F); Snake S; hatch(S); control_speed(S.speed); drawsnake(S, F); break; } case '2': flag = 0; break; default : break; } } closegraph(); } int main(void) { menu(); return 0; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持靠谱客。
最后
以上就是能干马里奥最近收集整理的关于利用C/C++实现贪吃蛇游戏的全部内容,更多相关利用C/C++实现贪吃蛇游戏内容请搜索靠谱客的其他文章。
发表评论 取消回复