再开一坑——实现简易的flappy bird游戏

最后一个游戏示例了。后续将介绍easyX以及使用easyX包装后的程序。
(图文无关)


没有新的前置知识。

显示小鸟

对flappy bird中小鸟的控制与之前在反弹球中介绍的差不多。我们还是用二维数组当作画布,先画一个随时间下落的小鸟,然后通过按下空格让小鸟的位置上升,代码如下。

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
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

#define High 15
#define Width 20

int bird_x, bird_y;
int canvas[High][Width];

void gotoxy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}

void HideCursor() {
CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void startup() {
memset(canvas, 0, sizeof(canvas));
bird_x = High / 2;
bird_y = 3;

canvas[bird_x][bird_y] = 1;
}

void show() {
gotoxy(0, 0);
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if (canvas[i][j] == 1)
printf("@");
else
printf(" ");
}
printf("\n");
}
}

void updateWithInput() {
char input;
if (_kbhit()) {
input = _getch();
if (input == ' ') {
canvas[bird_x][bird_y] = 0;
bird_x -= 3;
canvas[bird_x][bird_y] = 1;
}
}
}

void updateWithoutInput() {
Sleep(150);
canvas[bird_x][bird_y] = 0;
bird_x++;
canvas[bird_x][bird_y] = 1;

}

int main() {
startup();
HideCursor();
while (1) {
show();
updateWithInput();
updateWithoutInput();
}
return 0;
}

制造障碍物

其实没必要在设置的时候把整个障碍物都设置出来。想一下,flappy bird的障碍物是长什么样的?其实,我们只需要设定三个值就可以表示一个障碍物。

我们默认同屏有三个障碍物出现。笔者尝试用数组优化实现但是无果,最后选择使用单独的变量。

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
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>

#define High 20
#define Width 30
#define Barnum 3

int bird_x, bird_y;
int canvas[High][Width];

int bar1_y, bar2_y, bar3_y;
int bar1_xtop, bar2_xtop, bar3_xtop;
int bar1_xbottom, bar2_xbottom, bar3_xbottom;


void gotoxy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}

void HideCursor() {
CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void startup() {
memset(canvas, 0, sizeof(canvas));
bird_x = High / 2;
bird_y = 3;
canvas[bird_x][bird_y] = -1;

bar1_y = Width / 2 - 5;
bar2_y = bar1_y + 9;
bar3_y = bar2_y + 9;

int temp = rand() % int(High * 0.8);
bar1_xbottom = temp - High / 10;
bar1_xtop = temp + High / 10;

temp = rand() % int(High * 0.8);
bar2_xbottom = temp - High / 10;
bar2_xtop = temp + High / 10;

temp = rand() % int(High * 0.8);
bar3_xbottom = temp - High / 10;
bar3_xtop = temp + High / 10;

canvas[bar1_xtop][bar1_y] = 1;
canvas[bar1_xbottom][bar1_y] = 1;

canvas[bar2_xtop][bar2_y] = 1;
canvas[bar2_xbottom][bar2_y] = 1;

canvas[bar3_xtop][bar3_y] = 1;
canvas[bar3_xbottom][bar3_y] = 1;

for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 1;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 1;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 1;
}
}

}

void show() {
gotoxy(0, 0);
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if (canvas[i][j] == -1)
printf("@");
else if (canvas[i][j] == 1)
printf("*");
else
printf(" ");
}
printf("\n");
}


}

void updateWithInput() {
char input;
if (_kbhit()) {
input = _getch();
if (input == ' ') {
canvas[bird_x][bird_y] = 0;
bird_x -= 3;
canvas[bird_x][bird_y] = -1;
}
}
}

void updateWithoutInput() {
Sleep(150);
canvas[bird_x][bird_y] = 0;
bird_x++;
canvas[bird_x][bird_y] = -1;

}

int main() {
startup();
HideCursor();
while (1) {
show();
updateWithInput();
updateWithoutInput();
}
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
void updateWithoutInput() {
Sleep(200);
canvas[bird_x][bird_y] = 0;
bird_x++;
canvas[bird_x][bird_y] = -1;


for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 0;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 0;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 0;
}
}

canvas[bar1_xtop][bar1_y] = 0;
canvas[bar1_xbottom][bar1_y] = 0;
bar1_y--;
canvas[bar1_xtop][bar1_y] = 1;
canvas[bar1_xbottom][bar1_y] = 1;

canvas[bar2_xtop][bar2_y] = 0;
canvas[bar2_xbottom][bar2_y] = 0;
bar2_y--;
canvas[bar2_xtop][bar2_y] = 1;
canvas[bar2_xbottom][bar2_y] = 1;

canvas[bar3_xtop][bar3_y] = 0;
canvas[bar3_xbottom][bar3_y] = 0;
bar3_y--;
canvas[bar3_xtop][bar3_y] = 1;
canvas[bar3_xbottom][bar3_y] = 1;


for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 1;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 1;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 1;
}
}

}

其实只需要注意一点就好,就是在新位置绘画之前一定要先清除旧位置的内容。

判断碰撞,记分,循环出现,细节处理

这是最后的内容了。

由于三个障碍物会循环出现,判断时要略微注意。

小鸟的碰撞和用户的输入无关,所以我们修改updateWithoutInput函数。

记分和游戏失败是同时出现的。小鸟过障碍物只会有两个结果,如果过得去就+1分,过不去则宣告游戏失败。

同时要注意,小鸟触底也算游戏失败,如果小鸟试图飞出屏幕,那么我们应该把它限制在最高位置。具体参见代码:(无力优化,有点冗长)

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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>

#define High 20
#define Width 40
#define Barnum 3

int bird_x, bird_y;
int canvas[High][Width];

int bar1_y, bar2_y, bar3_y;
int bar1_xtop, bar2_xtop, bar3_xtop;
int bar1_xbottom, bar2_xbottom, bar3_xbottom;
int score;


void gotoxy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}

void HideCursor() {
CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void startup() {
memset(canvas, 0, sizeof(canvas));
bird_x = High / 2;
bird_y = 3;
canvas[bird_x][bird_y] = -1;

bar1_y = Width / 2 - 5;
bar2_y = bar1_y + 10;
bar3_y = bar2_y + 10;

int temp = rand() % int(High * 0.8);
bar1_xbottom = temp - High / 10;
bar1_xtop = temp + High / 10;

temp = rand() % int(High * 0.8);
bar2_xbottom = temp - High / 10;
bar2_xtop = temp + High / 10;

temp = rand() % int(High * 0.8);
bar3_xbottom = temp - High / 10;
bar3_xtop = temp + High / 10;

canvas[bar1_xtop][bar1_y] = 1;
canvas[bar1_xbottom][bar1_y] = 1;

canvas[bar2_xtop][bar2_y] = 1;
canvas[bar2_xbottom][bar2_y] = 1;

canvas[bar3_xtop][bar3_y] = 1;
canvas[bar3_xbottom][bar3_y] = 1;

for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 1;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 1;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 1;
}
}

score = 0;

}

void show() {
gotoxy(0, 0);
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if (canvas[i][j] == -1)
printf("@");
else if (canvas[i][j] == 1)
printf("*");
else
printf(" ");
}
printf("\n");
}

printf("得分: %d", score);
}

void updateWithInput() {
char input;
if (_kbhit()) {
input = _getch();
if (input == ' ') {
canvas[bird_x][bird_y] = 0;
if (bird_x - 3 >= 0)
bird_x -= 3;
else
bird_x = 0;
canvas[bird_x][bird_y] = -1;
}
}
}

void updateWithoutInput() {
Sleep(200);
canvas[bird_x][bird_y] = 0;
bird_x++;
canvas[bird_x][bird_y] = -1;

if (bird_x == High - 1) {
printf("GAME OVER\n");
system("pause");
exit(0);
}

if (bird_y == bar1_y) {
if ((bird_x >= bar1_xbottom) && (bird_y <= bar1_xtop))
score++;
else {
printf("GAME OVER\n");
system("pause");
exit(0);
}
}

if (bird_y == bar2_y) {
if ((bird_x >= bar2_xbottom) && (bird_y <= bar2_xtop))
score++;
else {
printf("GAME OVER\n");
system("pause");
exit(0);
}
}

if (bird_y == bar3_y) {
if ((bird_x >= bar3_xbottom) && (bird_y <= bar3_xtop))
score++;
else {
printf("GAME OVER\n");
system("pause");
exit(0);
}
}
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 0;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 0;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 0;
}
}

canvas[bar1_xtop][bar1_y] = 0;
canvas[bar1_xbottom][bar1_y] = 0;
bar1_y--;
canvas[bar1_xtop][bar1_y] = 1;
canvas[bar1_xbottom][bar1_y] = 1;

canvas[bar2_xtop][bar2_y] = 0;
canvas[bar2_xbottom][bar2_y] = 0;
bar2_y--;
canvas[bar2_xtop][bar2_y] = 1;
canvas[bar2_xbottom][bar2_y] = 1;

canvas[bar3_xtop][bar3_y] = 0;
canvas[bar3_xbottom][bar3_y] = 0;
bar3_y--;
canvas[bar3_xtop][bar3_y] = 1;
canvas[bar3_xbottom][bar3_y] = 1;


for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 1;
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 1;
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 1;
}
}


if (bar1_y < 0) {
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 0;
}
}
canvas[bar1_xtop][bar1_y] = 0;
canvas[bar1_xbottom][bar1_y] = 0;


bar1_y = Width;
int temp = rand() % int(High * 0.8);
bar1_xbottom = temp - High / 10;
bar1_xtop = temp + High / 10;

canvas[bar1_xtop][bar1_y] = 1;
canvas[bar1_xbottom][bar1_y] = 0;

for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar1_y) && ((i < bar1_xbottom) || (i > bar1_xtop)))
canvas[i][j] = 1;
}
}
}

if (bar2_y < 0) {
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 0;
}
}
canvas[bar2_xtop][bar2_y] = 0;
canvas[bar2_xbottom][bar2_y] = 0;


bar2_y = Width;
int temp = rand() % int(High * 0.8);
bar2_xbottom = temp - High / 10;
bar2_xtop = temp + High / 10;

canvas[bar2_xtop][bar2_y] = 1;
canvas[bar2_xbottom][bar2_y] = 0;

for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar2_y) && ((i < bar2_xbottom) || (i > bar2_xtop)))
canvas[i][j] = 1;
}
}
}

if (bar3_y < 0) {
for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 0;
}
}
canvas[bar3_xtop][bar3_y] = 0;
canvas[bar3_xbottom][bar3_y] = 0;


bar3_y = Width;
int temp = rand() % int(High * 0.8);
bar3_xbottom = temp - High / 10;
bar3_xtop = temp + High / 10;

canvas[bar3_xtop][bar3_y] = 1;
canvas[bar3_xbottom][bar3_y] = 0;

for (int i = 0; i < High; i++) {
for (int j = 0; j < Width; j++) {
if ((j == bar3_y) && ((i < bar3_xbottom) || (i > bar3_xtop)))
canvas[i][j] = 1;
}
}
}
}

int main() {
startup();
HideCursor();
while (1) {
show();
updateWithInput();
updateWithoutInput();
}
return 0;
}

-------------本文结束,感谢您的阅读转载请注明原作者及出处-------------


本文标题:再开一坑——实现简易的flappy bird游戏

文章作者:Shawn Zhou

发布时间:2018年08月07日 - 17:08

最后更新:2018年12月09日 - 13:12

原始链接:http://yoursite.com/2018/08/07/再开一坑——实现简易的flappy-bird游戏/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

知识无价,码字不易。对您有用,敬请打赏。金额随意,感谢关心。