C版本
點子
用遊戲函數框架和控制檯,寫一個flappy bird的程序,每次出現一個障礙物,玩家控制的小鳥(@)越過障礙物的缺口。
實現過程
1. 小鳥下落和操作上升
第一步實現一個簡單下落的小鳥@,小鳥自己有重力,會下落,每次y座標+1,按空格鍵上升。換句話說,這裏只給小鳥一種操作,上升。
#include <cstdio>
#include <windows.h>
#include <conio.h>
HANDLE hout; //定義標準輸出設備句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定義窗口緩衝區信息結構體
CONSOLE_CURSOR_INFO curInfo; //定義光標信息結構體
int bird_x, bird_y;
int width, height;
void gotoxy(int x, int y) { //移動光標
COORD pos = {x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void hideCursor() { //隱藏光標
curInfo.bVisible = 0;
curInfo.dwSize = 1;
SetConsoleCursorInfo(hout, &curInfo);
}
int initGame() {
hout = GetStdHandle(STD_OUTPUT_HANDLE); //獲得標準輸出設備句柄
GetConsoleScreenBufferInfo(hout, &csbi); //獲得窗口緩衝區信息
GetConsoleCursorInfo(hout, &curInfo); //獲得控制檯光標信息
width = 30, height = 20;
bird_x = width / 10, bird_y = 5;
hideCursor(); //隱藏光標
}
void endGame() {
CloseHandle(hout); //關閉標準輸出設備句柄
}
void updateWithInput() {
char input;
if (kbhit()) {
input = getch();
if (input == ' ') bird_y -= 2;
}
}
void updateWithoutInput() {
bird_y++; //小鳥逐漸下落
Sleep(150); //減緩下落
}
void show() {
gotoxy(0, 0);
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
if (i == bird_y && j == bird_x) printf("@"); //輸出小鳥
else printf(" ");
}
printf("\n");
}
}
int main() {
initGame();
while (1) {
show();
updateWithInput();
updateWithoutInput();
}
endGame();
return 0;
}
效果如下:
2. 輸出障礙物並讓其移動
同時顯示小鳥和靜止的障礙物,並讓障礙物自己從右向左移動。障礙物是從上面向下一截,從下面向上一截,中間有一個空缺。用bar_yTop,bar_yDown,bar1_x來描述障礙物。修改如下:
...
int bar_yTop, bar_yDown, bar_x; //障礙物
int initGame() {
...
bar_yTop = height / 4;
bar_yDown = height / 2;
bar_x = width - 5;
}
void updateWithoutInput() {
...
bar_x--; //障礙物逐漸右移
Sleep(200); //減緩下落
}
void show() {
...
else if ((i <= bar_yTop || i >= bar_yDown) && j == bar_x) printf("#");
...
}
...
3. 判斷障礙物是否與小鳥相撞
看小鳥是否從障礙物的縫隙中通過,還是發生碰撞。碰撞後退出遊戲循環。越過障礙顯示得分。
#include <cstdio>
#include <windows.h>
#include <conio.h>
#include <time.h>
HANDLE hout; //定義標準輸出設備句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定義窗口緩衝區信息結構體
CONSOLE_CURSOR_INFO curInfo; //定義光標信息結構體
int bird_x, bird_y;
int width, height;
int bar_yTop, bar_yDown, bar_x; //障礙物
int score;
int exitflag = 0; //退出遊戲循環標誌
void setSize(short len, short wid) { //設置窗口大小
COORD pos = {len, wid};
SMALL_RECT rc = {0, 0, len - 1, wid - 1}; //座標從0開始
// -- 設置窗口信息
// @param HANDLE [in] 窗口句柄
// @param bool [in] 意思不明,但在true時才起作用
// @param RECT * [in] 分別指定窗口左上角座標和右下角座標
// #return bool 成功返回非0值
SetConsoleWindowInfo(hout, true, &rc);
// -- 設置緩衝區大小
// -- 長和寬不得小於控制檯大小;不得小於系統最小限制。否則設置無效
// @param HANDLE [in] 窗口句柄
// @param COORD [in] 座標結構,包含長和寬
// #return bool 成功返回非0值
SetConsoleScreenBufferSize(hout, pos);
}
void gotoxy(int x, int y) { //移動光標
COORD pos = {x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void hideCursor() { //隱藏光標
curInfo.bVisible = 0;
curInfo.dwSize = 1;
SetConsoleCursorInfo(hout, &curInfo);
}
int initGame() {
hout = GetStdHandle(STD_OUTPUT_HANDLE); //獲得標準輸出設備句柄
GetConsoleScreenBufferInfo(hout, &csbi); //獲得窗口緩衝區信息
GetConsoleCursorInfo(hout, &curInfo); //獲得控制檯光標信息
hideCursor(); //隱藏光標
setSize(width * 2, height * 2); //設置窗口大小
width = 30, height = 20;
bird_x = width / 10, bird_y = 5;
bar_yTop = height / 4;
bar_yDown = height / 2;
bar_x = width - 5;
}
void endGame() {
CloseHandle(hout); //關閉標準輸出設備句柄
}
void updateWithInput() {
char input;
if (kbhit()) {
input = getch();
if (input == ' ') bird_y -= 2;
}
}
void updateWithoutInput() {
bird_y++; //小鳥逐漸下落
bar_x--; //障礙物逐漸右移
if (bar_x == bird_x) {
if (bird_y > bar_yTop && bird_y < bar_yDown) score++;
else {
printf("遊戲失敗!");
system("pause");
exitflag = 1;
}
}
Sleep(200); //減緩下落
}
void show() {
gotoxy(0, 0);
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
if (i == bird_y && j == bird_x) printf("@");
else if ((i <= bar_yTop || i >= bar_yDown) && j == bar_x) printf("#");
else printf(" ");
}
printf("\n");
}
printf("得分爲:%d\n", score);
}
int main() {
initGame();
while (1) {
show();
updateWithInput();
updateWithoutInput();
if (exitflag) break; //遊戲失敗, 滿足退出條件
}
endGame();
return 0;
}
4. 障礙物循環出現
類似飛機遊戲中敵機被擊落或者超出屏幕範圍後重新出現敵機,這裏讓障礙物在左邊消失後在最右邊循環出現。用rand()隨機產生障礙物的縫隙的位置和大小,當然,要讓小鳥通過。
void updateWithoutInput() {
bird_y++; //小鳥逐漸下落
bar_x--; //障礙物逐漸右移
if (bar_x < 0) { //重新生成一個障礙物
bar_x = width;
int temp = rand() % (int)(height * 0.8);
bar_yTop = temp - height / 10 - 1;
bar_yDown = temp + height / 10 + 1;
}
...
}
思考:
- 如何同時顯示多根柱子?提示:用x座標數組合y座標數組;或者用結構體。
- 模擬重力效果,小鳥加速下落。