c语言版 flappy bird

99ANYc3cd6
预计阅读时长 28 分钟
位置: 首页 C语言 正文

EasyX 是一个专门为 C++ 设计的、简单易用的图形库,但它也兼容 C 语言,如果你在 Windows 环境下开发,这是一个非常好的选择,因为它能让你专注于游戏逻辑,而不用去处理复杂的 Windows API 或 DirectX。

c语言版 flappy bird
(图片来源网络,侵删)

第一步:环境准备

  1. 安装 EasyX:

    • 访问 EasyX 官网
    • 下载并安装最新版本的 EasyX,安装过程非常简单,一路“下一步”即可,它会自动配置好你的 Visual Studio(或其他支持的 C++ 编译器)。
  2. 创建项目:

    • 打开 Visual Studio。
    • 创建一个新的“控制台应用程序”项目。
    • 在项目属性中,确保将“字符集”设置为“使用多字节字符集”,这可以避免一些编码问题。

第二步:完整 C 语言代码

将以下代码复制到你的 .c 文件中(flappy_bird.c)。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>      // 用于 _kbhit() 和 _getch()
#include <graphics.h>   // EasyX 图形库头文件
#include <time.h>       // 用于随机数生成
// --- 游戏常量 ---
#define SCREEN_WIDTH    800
#define SCREEN_HEIGHT   600
#define BIRD_SIZE       30
#define GRAVITY         0.5
#define JUMP_FORCE      -8
#define PIPE_WIDTH      80
#define PIPE_GAP        180
#define PIPE_SPEED      3
#define GROUND_HEIGHT   50
#define GROUND_Y        (SCREEN_HEIGHT - GROUND_HEIGHT)
#define BIRD_START_X    200
#define BIRD_START_Y    SCREEN_HEIGHT / 2
// --- 游戏状态 ---
typedef struct {
    int x;
    int y;
    double velocity;
} Bird;
typedef struct {
    int x;
    int top_height;
} Pipe;
// --- 函数声明 ---
void initGame(Bird* bird, Pipe* pipes);
void updateGame(Bird* bird, Pipe* pipes, int* score, int* game_over);
void drawGame(const Bird* bird, const Pipe* pipes, int score, int game_over);
void drawBird(const Bird* bird);
void drawPipes(const Pipe* pipes);
void drawGround();
void drawScore(int score);
void drawGameOver(int score);
// --- 主函数 ---
int main() {
    // 初始化图形窗口
    initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
    // 设置随机数种子
    srand((unsigned int)time(NULL));
    Bird bird;
    Pipe pipes[3]; // 使用3个管道实现循环滚动
    int score = 0;
    int game_over = 0;
    // 初始化游戏
    initGame(&bird, pipes);
    // 游戏主循环
    while (1) {
        // 更新游戏状态
        if (!game_over) {
            updateGame(&bird, pipes, &score, &game_over);
        }
        // 绘制游戏画面
        drawGame(&bird, pipes, score, game_over);
        // 控制帧率,并处理退出
        Sleep(20); // 约 50 FPS
        if (_kbhit()) {
            char ch = _getch();
            if (ch == 27) { // ESC 键退出
                break;
            }
            if (ch == ' ' && game_over) { // 空格键重新开始
                initGame(&bird, pipes);
                score = 0;
                game_over = 0;
            }
            if (ch == ' ' && !game_over) { // 空格键跳跃
                bird.velocity = JUMP_FORCE;
            }
        }
    }
    // 关闭图形窗口
    closegraph();
    return 0;
}
// --- 函数实现 ---
// 初始化游戏状态
void initGame(Bird* bird, Pipe* pipes) {
    bird->x = BIRD_START_X;
    bird->y = BIRD_START_Y;
    bird->velocity = 0;
    // 初始化3个管道,让它们均匀分布
    for (int i = 0; i < 3; i++) {
        pipes[i].x = SCREEN_WIDTH + i * (SCREEN_WIDTH / 3);
        pipes[i].top_height = rand() % (SCREEN_HEIGHT - PIPE_GAP - GROUND_HEIGHT - 100) + 50;
    }
}
// 更新游戏逻辑
void updateGame(Bird* bird, Pipe* pipes, int* score, int* game_over) {
    // 1. 更新小鸟
    bird->velocity += GRAVITY;
    bird->y += (int)bird->velocity;
    // 2. 更新管道
    for (int i = 0; i < 3; i++) {
        pipes[i].x -= PIPE_SPEED;
        // 如果管道移出屏幕,将其重置到最右边
        if (pipes[i].x + PIPE_WIDTH < 0) {
            pipes[i].x = SCREEN_WIDTH;
            pipes[i].top_height = rand() % (SCREEN_HEIGHT - PIPE_GAP - GROUND_HEIGHT - 100) + 50;
        }
        // 3. 检测碰撞
        // 管道x坐标范围
        if (bird->x + BIRD_SIZE > pipes[i].x && bird->x < pipes[i].x + PIPE_WIDTH) {
            // 检测是否撞到上管道或下管道
            if (bird->y < pipes[i].top_height || bird->y + BIRD_SIZE > pipes[i].top_height + PIPE_GAP) {
                *game_over = 1;
            }
        }
        // 4. 计分
        // 当小鸟通过管道时加分
        if (bird->x == pipes[i].x + PIPE_WIDTH / 2) {
            (*score)++;
        }
    }
    // 5. 检测地面和天花板碰撞
    if (bird->y + BIRD_SIZE > GROUND_Y || bird->y < 0) {
        *game_over = 1;
    }
}
// 绘制游戏画面
void drawGame(const Bird* bird, const Pipe* pipes, int score, int game_over) {
    // 清屏,填充天蓝色背景
    setfillcolor(RGB(135, 206, 235));
    solidrectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    // 绘制游戏元素
    drawPipes(pipes);
    drawBird(bird);
    drawGround();
    drawScore(score);
    if (game_over) {
        drawGameOver(score);
    }
}
// 绘制小鸟(一个黄色的圆形)
void drawBird(const Bird* bird) {
    setfillcolor(YELLOW);
    solidcircle(bird->x + BIRD_SIZE / 2, bird->y + BIRD_SIZE / 2, BIRD_SIZE / 2);
    // 简单的眼睛
    setfillcolor(BLACK);
    solidcircle(bird->x + BIRD_SIZE / 2 + 5, bird->y + BIRD_SIZE / 2 - 5, 3);
}
// 绘制管道(绿色的矩形)
void drawPipes(const Pipe* pipes) {
    setfillcolor(GREEN);
    for (int i = 0; i < 3; i++) {
        // 上管道
        solidrectangle(pipes[i].x, 0, pipes[i].x + PIPE_WIDTH, pipes[i].top_height);
        // 下管道
        solidrectangle(pipes[i].x, pipes[i].top_height + PIPE_GAP, pipes[i].x + PIPE_WIDTH, SCREEN_HEIGHT);
    }
}
// 绘制地面
void drawGround() {
    setfillcolor(BROWN);
    solidrectangle(0, GROUND_Y, SCREEN_WIDTH, SCREEN_HEIGHT);
}
// 绘制分数
void drawScore(int score) {
    setbkmode(TRANSPARENT); // 设置文字背景透明
    settextcolor(WHITE);
    settextstyle(50, 0, _T("Arial"));
    TCHAR score_str[16];
    _stprintf(score_str, _T("%d"), score);
    outtextxy(SCREEN_WIDTH / 2 - 20, 50, score_str);
}
// 绘制游戏结束画面
void drawGameOver(int score) {
    setbkmode(TRANSPARENT);
    settextcolor(WHITE);
    settextstyle(60, 0, _T("Arial"));
    outtextxy(SCREEN_WIDTH / 2 - 120, SCREEN_HEIGHT / 2 - 100, _T("Game Over"));
    settextstyle(30, 0, _T("Arial"));
    TCHAR score_str[32];
    _stprintf(score_str, _T("Final Score: %d"), score);
    outtextxy(SCREEN_WIDTH / 2 - 100, SCREEN_HEIGHT / 2, score_str);
    outtextxy(SCREEN_WIDTH / 2 - 120, SCREEN_HEIGHT / 2 + 50, _T("Press SPACE to restart"));
}

第三步:代码解释

头文件和常量

  • #include <graphics.h>: 引入 EasyX 图形库。
  • #include <conio.h>: 用于检测键盘输入(_kbhit, _getch),无需按回车即可响应。
  • #define ...: 定义了游戏中用到的各种尺寸和速度常量,方便统一修改。

游戏状态结构体

  • Bird: 存储小鸟的位置 (x, y) 和垂直速度 (velocity),使用 double 存储速度可以使运动更平滑。
  • Pipe: 存储管道的 x 坐标和上管道的高度 (top_height),下管道的高度可以通过 top_height + PIPE_GAP 计算得出。

main() 函数 - 游戏循环

这是游戏的核心。

c语言版 flappy bird
(图片来源网络,侵删)
  1. initgraph(): 创建一个 800x600 的窗口。
  2. srand(): 初始化随机数生成器,用于随机生成管道的高度。
  3. while(1): 无限循环,持续运行游戏。
  4. 更新: updateGame() 函数负责计算所有物体的新位置、检测碰撞、更新分数。
  5. 绘制: drawGame() 函数负责清空屏幕并重新绘制所有游戏元素(背景、管道、小鸟、地面、分数)。
  6. 输入与帧率控制:
    • Sleep(20): 暂停 20 毫秒,将游戏帧率控制在约 50 FPS,避免游戏运行过快。
    • _kbhit(): 检查是否有键盘输入。
    • _getch(): 获取按下的键。
    • ESC: 退出游戏。
    • 空格键: 游戏中控制小鸟跳跃;游戏结束后重新开始。

initGame() - 初始化

设置小鸟的初始位置和速度,并初始化3个管道的位置,让它们均匀分布在屏幕上,形成连续的“管道流”。

updateGame() - 核心逻辑

  • 小鸟物理: 应用重力 (velocity += GRAVITY),并根据速度更新位置 (y += velocity)。
  • 管道移动: 将所有管道向左移动 (x -= PIPE_SPEED),如果管道完全移出屏幕左侧,就将其重置到屏幕最右侧,并随机生成一个新的高度,实现循环。
  • 碰撞检测:
    • 管道: 判断小鸟是否在管道的 x 轴范围内,并且是否在上下管道之间的 y 轴范围之外。
    • 地面/天花板: 判断小鸟的 y 坐标是否超出地面或低于屏幕顶部。
  • 计分: 当小鸟的 x 坐标与管道中心线对齐时,认为小鸟成功通过一个管道,分数加一。

drawGame() 及其辅助函数

  • setfillcolor(): 设置填充颜色。
  • solidrectangle(): 绘制一个填充的矩形(用于背景、管道、地面)。
  • solidcircle(): 绘制一个填充的圆(用于小鸟)。
  • setbkmode(TRANSPARENT): 设置文字背景为透明,这样文字就不会覆盖背景图。
  • settextstyle(): 设置字体、大小和样式。
  • outtextxy(): 在指定位置绘制文字(用于显示分数和 "Game Over")。

第四步:如何编译和运行

  1. 确保你已经按照第一步安装了 EasyX。
  2. 将上述代码保存为 flappy_bird.c 文件,并添加到你的 Visual Studio 项目中。
  3. 确保 Visual Studio 的项目配置中,字符集 设置为 “使用多字节字符集”
  4. 点击“生成” -> “生成解决方案” (F7) 或直接按 Ctrl + F5 运行程序。

你应该就能看到一个窗口弹出来,玩这个 C 语言版的 Flappy Bird 了!祝你玩得开心!

c语言版 flappy bird
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
织梦怎样添加nofollow
« 上一篇 2025-12-23
dede wap如何调用栏目文章列表?
下一篇 » 2025-12-23

相关文章

取消
微信二维码
支付宝二维码

目录[+]