目录

C游戏开发零基础手写完整飞机大战游戏基于EasyX图形库详细注释源码分享

【C++游戏开发】零基础手写完整飞机大战游戏(基于EasyX图形库/详细注释/源码分享)

一、开发环境与资源准备

1.1 环境要求

  • Visual Studio 2019+ (推荐2022)
  • EasyX图形库 (官网下载适配VS版本)
  • Windows SDK (安装VS时勾选)

1.2 资源文件

在项目目录创建 res 文件夹,存放以下素材(素材自备):

  • plane.png 玩家飞机(50x50)
  • enemy.png 敌机(50x50)
  • bullet.png 子弹(10x20)
  • bg.jpg 滚动背景(600x700)
  • boom.wav 爆炸音效

二、完整游戏代码实现(500行精简化)

2.1 头文件与常量定义

#include <graphics.h>
#include <conio.h>
#include <Windows.h>
#include <list>
#include <ctime>
using namespace std;

// 窗口尺寸
const int WIDTH = 600;
const int HEIGHT = 700;

// 游戏对象基类
class GameObject {
public:
    int x, y;
    int speed;
    bool alive;
    IMAGE img;
    GameObject(const wchar_t* path, int speed = 0) {
        loadimage(&img, path);
        this->speed = speed;
        alive = false;
    }
};

2.2 游戏管理器类(核心逻辑)

class GameManager {
private:
    GameObject* player;                 // 玩家飞机
    list<GameObject*> enemies;          // 敌机容器
    list<GameObject*> bullets;          // 子弹容器
    int score;                          // 游戏得分
    IMAGE bgImg;                        // 背景图片
    int bgOffset;                       // 背景滚动偏移
    
public:
    GameManager() {
        srand((unsigned)time(NULL));
        loadimage(&bgImg, L"res/bg.jpg");
        initGame();
    }

    // 初始化游戏
    void initGame() {
        score = 0;
        bgOffset = 0;
        
        // 创建玩家对象
        player = new GameObject(L"res/plane.png", 8);
        player->x = WIDTH/2 - 25;
        player->y = HEIGHT - 100;
        player->alive = true;

        // 清空容器
        clearAll();
    }

    // 游戏主循环
    void run() {
        DWORD lastTime = GetTickCount();
        while (true) {
            // 60帧控制
            if (GetTickCount() - lastTime < 16) continue;
            lastTime = GetTickCount();

            processInput();
            update();
            render();
        }
    }

    // 输入处理(详细代码见下文)
    void processInput();
    
    // 游戏逻辑更新(详细代码见下文)
    void update();
    
    // 渲染绘制(详细代码见下文)
    void render();

    // 清空游戏对象
    void clearAll() {
        for (auto& e : enemies) delete e;
        for (auto& b : bullets) delete b;
        enemies.clear();
        bullets.clear();
    }

    ~GameManager() {
        delete player;
        clearAll();
    }
};

2.3 输入处理模块

void GameManager::processInput() {
    // 左右移动
    if (GetAsyncKeyState(VK_LEFT) & 0x8000) {
        player->x = max(0, player->x - player->speed);
    }
    if (GetAsyncKeyState(VK_RIGHT) & 0x8000) {
        player->x = min(WIDTH - 50, player->x + player->speed);
    }

    // 空格射击(冷却控制)
    static DWORD lastShoot = 0;
    if (GetAsyncKeyState(VK_SPACE) && GetTickCount() - lastShoot > 200) {
        GameObject* bullet = new GameObject(L"res/bullet.png", 10);
        bullet->x = player->x + 20;
        bullet->y = player->y - 20;
        bullet->alive = true;
        bullets.push_back(bullet);
        lastShoot = GetTickCount();
    }
}

2.4 游戏逻辑更新

void GameManager::update() {
    // 背景滚动
    bgOffset += 2;
    if (bgOffset >= HEIGHT) bgOffset = 0;

    // 生成敌机(随机间隔)
    if (rand() % 100 < 3) {
        GameObject* enemy = new GameObject(L"res/enemy.png", 3);
        enemy->x = rand() % (WIDTH - 50);
        enemy->y = -50;
        enemy->alive = true;
        enemies.push_back(enemy);
    }

    // 更新子弹
    auto bit = bullets.begin();
    while (bit != bullets.end()) {
        (*bit)->y -= (*bit)->speed;
        if ((*bit)->y < -20) {
            delete *bit;
            bit = bullets.erase(bit);
        } else {
            ++bit;
        }
    }

    // 更新敌机与碰撞检测
    auto eit = enemies.begin();
    while (eit != enemies.end()) {
        (*eit)->y += (*eit)->speed;
        
        // 出界检测
        if ((*eit)->y > HEIGHT) {
            delete *eit;
            eit = enemies.erase(eit);
            continue;
        }

        // 子弹碰撞检测
        bool hit = false;
        for (auto& bullet : bullets) {
            if (checkCollision(*eit, bullet)) {
                hit = true;
                bullet->alive = false;
                score += 10;
                // 播放爆炸音效
                PlaySound(L"res/boom.wav", NULL, SND_FILENAME | SND_ASYNC);
                break;
            }
        }

        if (hit) {
            delete *eit;
            eit = enemies.erase(eit);
        } else {
            ++eit;
        }
    }
}

// 碰撞检测(矩形粗略检测)
bool checkCollision(GameObject* a, GameObject* b) {
    return abs(a->x - b->x) < 40 && 
           abs(a->y - b->y) < 40;
}

2.5 画面渲染模块

void GameManager::render() {
    BeginBatchDraw();

    // 绘制背景(滚动效果)
    putimage(0, bgOffset, &bgImg);
    putimage(0, bgOffset - HEIGHT, &bgImg);

    // 绘制玩家
    if (player->alive) {
        putimage(player->x, player->y, &player->img);
    }

    // 绘制敌机
    for (auto& e : enemies) {
        putimage(e->x, e->y, &e->img);
    }

    // 绘制子弹
    for (auto& b : bullets) {
        putimage(b->x, b->y, &b->img);
    }

    // 绘制UI
    settextcolor(0x00FF00);
    settextstyle(20, 0, L"Consolas");
    wchar_t text[32];
    swprintf_s(text, L"Score: %d", score);
    outtextxy(10, 10, text);

    EndBatchDraw();
}

2.6 主函数入口

int main() {
    initgraph(WIDTH, HEIGHT);  // 创建窗口
    GameManager game;          // 游戏管理器
    game.run();                // 启动游戏
    closegraph();              // 关闭图形
    return 0;
}

三、代码解析与运行效果

3.1 关键实现技术

  1. 面向对象设计 :使用GameObject基类管理游戏实体
  2. STL容器 :list实现动态对象管理
  3. 双缓冲绘图 :BeginBatchDraw/EndBatchDraw消除闪烁
  4. 资源管理 :统一加载图片音效资源
  5. 帧率控制 :GetTickCount实现60FPS稳定

3.2 游戏效果演示

  • 左右方向键控制飞机移动
  • 空格键发射子弹(200ms冷却)
  • 自动生成随机位置敌机
  • 击中敌机获得分数并播放音效
  • 背景星空持续滚动

四、常见问题解决方案

Q1:图片加载失败

  • 检查 res 文件夹是否在项目根目录
  • 确认图片格式为png/jpg
  • 右键图片文件→属性→取消"阻止"勾选

Q2:音效无法播放

  • 确认 .wav 文件为PCM格式
  • 使用Audacity等工具转换音频格式
  • 检查PlaySound参数是否正确

Q3:游戏运行卡顿

  • 关闭杀毒软件实时监控
  • 降低背景图片分辨率
  • 减少同时存在的对象数量

五、项目扩展方向

  1. 增加玩家生命值系统
  2. 实现BOSS战和特殊武器
  3. 添加关卡难度递增
  4. 集成分数排行榜功能
  5. 支持手柄/触摸操作