温馨提示×

CentOS下C++游戏开发实战教程

小樊
39
2025-12-29 07:43:39
栏目: 编程语言

CentOS 下 C++ 游戏开发实战教程

一 环境搭建与工具链

  • 更新系统并安装基础工具:
    • 命令:sudo yum update
    • 命令:sudo yum groupinstall "Development Tools" -y
    • 命令:sudo yum install -y gcc gcc-c++ make cmake gdb git vim
  • 可选:升级 GCC 以获得 C++17/20 支持(CentOS 7/8 默认版本较低)
    • 命令:sudo yum install -y centos-release-scl
    • 命令:sudo yum install -y devtoolset-11(或 devtoolset-9
    • 启用:scl enable devtoolset-11 bash(当前会话生效;如需持久化,可写入 ~/.bashrc
  • 验证工具链:
    • 命令:gcc -vg++ -vcmake --versiongdb -v
  • 建议编辑器与远程开发:
    • 安装 VS Code,配合 Remote - SSH 插件在本地编辑、远程编译运行
    • 或安装 Qt Creatorsudo yum install -y qt-creator(图形化项目管理与调试)

二 项目骨架与构建系统

  • 目录结构建议:
    • src/include/tests/third_party/CMakeLists.txtbuild/
  • 最小 CMakeLists.txt(C++17)
    cmake_minimum_required(VERSION 3.16)
    project(Game LANGUAGES CXX)
    
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    
    add_executable(game main.cpp)
    
    # 可选:单元测试
    # enable_testing()
    # add_subdirectory(tests)
    
  • 构建与运行
    mkdir -p build && cd build
    cmake -DCMAKE_BUILD_TYPE=Release ..
    make -j$(nproc)
    ./game
    
  • 调试与性能分析
    • 调试:gdb ./game
    • 内存与热点:valgrind --leak-check=full ./game
    • 编译期优化:在 CMakeLists.txt 中为 Release 目标添加 -O2/-O3

三 实战一 终端小游戏 猜数字

  • 目标:练习输入输出、循环与分支、随机数
  • 代码:guess.cpp
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    
    int main() {
        std::srand(static_cast<unsigned>(std::time(nullptr)));
        int number = std::rand() % 100 + 1;
        int guess = 0;
    
        std::cout << "Guess a number between 1 and 100:\n";
    
        do {
            std::cout << "> ";
            std::cin >> guess;
    
            if (guess > number) {
                std::cout << "Too high.\n";
            } else if (guess < number) {
                std::cout << "Too low.\n";
            } else {
                std::cout << "That's right!\n";
            }
        } while (guess != number);
    
        return 0;
    }
    
  • 构建与运行
    g++ -std=c++17 -O2 -o guess guess.cpp
    ./guess
    
  • 要点
    • 使用 std::srand + std::time(nullptr) 初始化随机种子
    • do-while 保证至少一次输入
    • 条件分支给出提示,直到猜中为止

四 实战二 终端小游戏 贪吃蛇

  • 方案选择
    • 在 Linux 终端使用 ncurses 库实现非阻塞输入与清屏
    • 安装:sudo yum install -y ncurses-devel
  • 代码:snake.cpp(简化版,WASD 控制,无墙碰撞优化)
    #include <iostream>
    #include <vector>
    #include <ncurses.h>
    #include <unistd.h>
    #include <cstdlib>
    #include <ctime>
    
    struct Point { int x, y; };
    
    enum Dir { STOP = 0, LEFT, RIGHT, UP, DOWN };
    
    int main() {
        initscr();
        cbreak(); noecho();
        keypad(stdscr, TRUE);
        curs_set(0);
        timeout(100); // 100ms 刷新
    
        int w = 40, h = 20;
        WINDOW *win = newwin(h, w, 0, 0);
        box(win, 0, 0);
    
        std::srand(static_cast<unsigned>(time(nullptr)));
        Dir dir = STOP;
        Point head{w/2, h/2};
        std::vector<Point> body;
        int score = 0;
    
        auto spawnFood = [&]() {
            Point f;
            do {
                f.x = 1 + rand() % (w-2);
                f.y = 1 + rand() % (h-2);
            } while (std::find(body.begin(), body.end(), f) != body.end() ||
                     (f.x == head.x && f.y == head.y));
            return f;
        };
        Point food = spawnFood();
    
        while (true) {
            int ch = getch();
            switch (ch) {
                case 'q': case 'Q': goto end;
                case KEY_LEFT:  if (dir != RIGHT) dir = LEFT;  break;
                case KEY_RIGHT: if (dir != LEFT)  dir = RIGHT; break;
                case KEY_UP:    if (dir != DOWN)  dir = UP;    break;
                case KEY_DOWN:  if (dir != UP)    dir = DOWN;  break;
                case 'a': if (dir != RIGHT) dir = LEFT;  break;
                case 'd': if (dir != LEFT)  dir = RIGHT; break;
                case 'w': if (dir != DOWN)  dir = UP;    break;
                case 's': if (dir != UP)    dir = DOWN;  break;
            }
    
            Point newHead = head;
            switch (dir) {
                case LEFT:  newHead.x--; break;
                case RIGHT: newHead.x++; break;
                case UP:    newHead.y--; break;
                case DOWN:  newHead.y++; break;
                default: break;
            }
    
            // 撞墙或自撞
            if (newHead.x <= 0 || newHead.x >= w-1 ||
                newHead.y <= 0 || newHead.y >= h-1 ||
                std::find(body.begin(), body.end(), newHead) != body.end()) {
                break;
            }
    
            body.insert(body.begin(), head);
            if (newHead.x == food.x && newHead.y == food.y) {
                score++;
                food = spawnFood();
            } else {
                body.pop_back();
            }
            head = newHead;
    
            werase(win);
            box(win, 0, 0);
            mvwprintw(win, food.y, food.x, "*");
            for (size_t i = 0; i < body.size(); ++i) {
                mvwprintw(win, body[i].y, body[i].x, "o");
            }
            mvwprintw(win, head.y, head.x, "@");
            mvwprintw(win, h-1, 1, "Score: %d  WASD/q", score);
            wrefresh(win);
            usleep(80000);
        }
    
    end:
        delwin(win);
        endwin();
        std::cout << "Game Over! Score: " << score << "\n";
        return 0;
    }
    
  • 构建与运行
    g++ -std=c++17 -O2 -lncurses -o snake snake.cpp
    ./snake
    
  • 要点
    • 使用 ncursesinitscrcbreaknoechokeypadtimeoutwrefresh
    • 非阻塞输入通过 timeout(ms) 实现
    • 蛇身用 std::vector<Point> 管理,食物随机生成并避免与蛇身重叠

五 进阶路线与常见问题

  • 进阶路线
    • 图形渲染:基于 SDL2(多媒体/事件/计时器完善,适合 2D 小游戏)
    • 跨平台 GUI:使用 Qt(QWidget/QML,适合工具链与简单 2D 游戏)
    • 网络联机:基于 TCP/UDP 的异步 I/O(如 epoll),注意粘包、超时、序列化与心跳
    • 性能优化:编译器 -O2/-O3、内联与数据局部性、对象池、帧率稳定与固定时间步
  • 常见问题
    • 终端输入不响应:确认已调用 cbreak()noecho()keypad(stdscr, TRUE) 并设置 timeout
    • 中文或宽字符乱码:终端需设置 UTF-8,ncurses 以字节绘制为主,建议使用 ASCII/半角符号
    • 旧版 GCC 不支持 C++17:启用 devtoolset-9/11 后再编译
    • 构建失败提示找不到库:安装对应 -devel 包(如 ncurses-devel),并在 CMake 中使用 find_package(Curses REQUIRED) 链接
    • 调试困难:使用 gdb 断点/观察点,配合 valgrind 排查内存与越界问题

0