用C++手搓一个贪吃蛇?

一、前言:为什么要用C++写游戏?

"都2024年了还用C++搞游戏?Unity不香吗?"------如果你这么想,咱们得聊聊。用C++搓游戏就像手动挡飙车:虐,但爽!它能让你真正理解内存管理、帧率控制、算法优化 这些底层逻辑。今天咱们不用任何游戏引擎,就用最朴素的coutwhile循环,在控制台里搞个能玩的贪吃蛇!(温馨提示:本文代码在VS2022和GCC 13下开发测试)


二、开发环境准备

1. 编译器选择
  • Windows党 :装个Visual Studio 2022,勾选"C++桌面开发"
  • Linux/Mac党sudo apt install g++ 或者 brew install gcc
2. 代码规范
  • 使用C++11及以上标准(别问,问就是auto和范围for循环真香)
  • 禁止魔法数字(比如直接把地图宽度写成20,等着被同事打死吧)

三、手撕代码环节

Step 1:定义游戏世界(20x20的战场)
cpp 复制代码
#include <iostream>
#include <conio.h>    // Windows专用,Linux/macOS用ncurses
#include <windows.h>  // Sleep函数
#include <vector>
#include <cstdlib>    // rand()
#include <ctime>     // time()

using namespace std;

// 常量定义(拒绝魔法数字!)
const int WIDTH = 20;         // 地图宽度
const int HEIGHT = 20;        // 地图高度
const char SNAKE_HEAD = '@';  // 蛇头
const char SNAKE_BODY = 'o';  // 蛇身
const char FOOD = '$';        // 食物
const char WALL = '#';        // 墙壁

// 坐标结构体
struct Point {
    int x, y;
    Point(int _x, int _y) : x(_x), y(_y) {}
};
Step 2:初始化游戏状态
cpp 复制代码
vector<Point> snake;   // 蛇身体坐标
Point food(0, 0);      // 食物位置
char direction = 'd';  // 初始方向:右
int score = 0;         // 得分
bool gameOver = false; // 游戏结束标志

// 生成随机食物
void generateFood() {
    // 防止食物生成在蛇身上
    do {
        food.x = rand() % (WIDTH - 2) + 1;
        food.y = rand() % (HEIGHT - 2) + 1;
    } while (any_of(snake.begin(), snake.end(), [](Point p) {
        return p.x == food.x && p.y == food.y;
    }));
}

// 初始化游戏
void initGame() {
    srand(time(nullptr));  // 随机种子
    snake.clear();
    snake.push_back(Point(WIDTH/2, HEIGHT/2));  // 蛇头初始位置居中
    generateFood();
}
Step 3:渲染游戏画面(全靠cout输出)
cpp 复制代码
void draw() {
    system("cls");  // 清屏(Windows专属,Linux换成"clear")

    // 画顶部墙壁
    for (int i = 0; i < WIDTH; ++i) cout << WALL;
    cout << endl;

    // 画中间区域
    for (int y = 1; y < HEIGHT-1; ++y) {
        cout << WALL;  // 左侧墙
        for (int x = 1; x < WIDTH-1; ++x) {
            bool isSnake = any_of(snake.begin(), snake.end(), [x, y](Point p) {
                return p.x == x && p.y == y;
            });
            
            if (isSnake) {
                // 判断是否是蛇头
                cout << (x == snake[0].x && y == snake[0].y ? SNAKE_HEAD : SNAKE_BODY);
            } else if (x == food.x && y == food.y) {
                cout << FOOD;
            } else {
                cout << " ";
            }
        }
        cout << WALL << endl;  // 右侧墙
    }

    // 画底部墙壁
    for (int i = 0; i < WIDTH; ++i) cout << WALL;
    cout << "\nScore: " << score << endl;
}
Step 4:处理输入(方向键控制)
cpp 复制代码
void input() {
    if (_kbhit()) {  // 检测键盘输入(Windows专属)
        switch (_getch()) {
            case 'w': if (direction != 's') direction = 'w'; break;
            case 's': if (direction != 'w') direction = 's'; break;
            case 'a': if (direction != 'd') direction = 'a'; break;
            case 'd': if (direction != 'a') direction = 'd'; break;
            case 'x': gameOver = true; break;  // 按x退出
        }
    }
}
Step 5:更新游戏逻辑(碰撞检测、移动等)
cpp 复制代码
void update() {
    // 计算新蛇头位置
    Point newHead = snake[0];
    switch (direction) {
        case 'w': newHead.y--; break;
        case 's': newHead.y++; break;
        case 'a': newHead.x--; break;
        case 'd': newHead.x++; break;
    }

    // 撞墙检测
    if (newHead.x <= 0 || newHead.x >= WIDTH-1 || 
        newHead.y <= 0 || newHead.y >= HEIGHT-1) {
        gameOver = true;
        return;
    }

    // 撞自己检测
    for (auto& p : snake) {
        if (p.x == newHead.x && p.y == newHead.y) {
            gameOver = true;
            return;
        }
    }

    // 移动蛇身
    snake.insert(snake.begin(), newHead);

    // 吃食物判断
    if (newHead.x == food.x && newHead.y == food.y) {
        score += 10;
        generateFood();
    } else {
        snake.pop_back();  // 没吃到食物时去掉尾巴
    }
}
Step 6:主游戏循环
cpp 复制代码
int main() {
    initGame();
    while (!gameOver) {
        draw();
        input();
        update();
        Sleep(200);  // 控制游戏速度(200毫秒/帧)
    }
    cout << "Game Over! Final Score: " << score << endl;
    return 0;
}

四、如何运行这个"复古版"贪吃蛇

Windows用户:
  1. 用Visual Studio新建空项目
  2. 把代码粘贴到main.cpp
  3. 按F5运行(如果报错,检查是否勾选"使用多字节字符集")
Linux/macOS用户:
  1. 安装ncurses库:sudo apt install libncurses5-dev
  2. conio.h相关代码替换成ncurses实现(需要可以留言,我另写教程)

五、功能扩展指南(装X必备)

  1. 增加难度等级:随着分数提升缩短Sleep时间
  2. 存档功能:把snake vector写入文件
  3. 双人对战:用WASD和方向键控制两条蛇
  4. 图形界面:集成SDL2库替换cout渲染

六、避雷指南(泪目了)

  1. 别在update里调用draw:会导致闪烁,帧率不稳
  2. 蛇身移动顺序:先插头再删尾,顺序反了会抽搐
  3. 随机数陷阱:不用srand(time(nullptr))会导致每次食物位置相同
  4. 撞墙检测边界:WIDTH-1和HEIGHT-1是重点,直接写WIDTH等着看蛇穿墙

七、结语

虽然这个控制台版贪吃蛇简陋得像个出土文物,但它包含了游戏循环、状态管理、输入处理这些核心概念。下次咱们可以试试用SDL2搞个带画面的版本------到时候你就能理直气壮地把这个代码贴到GitHub,标题写上"3A大作早期开发版本"了(手动狗头)。

有问题欢迎拍砖,代码要是跑不起来... 肯定是你键盘的问题(逃)

相关推荐
jia_jia_LL几秒前
备战蓝桥杯国赛第一天-atcoder-beginner-contest404
c++·算法·蓝桥杯·图论
喜欢吃燃面7 分钟前
数据结构之二叉树(4)
c语言·数据结构·c++·学习
renhl2521 小时前
C++11新特性_标准库_正则表达式库
c++
HelloRevit1 小时前
DXFViewer进行中 : ->封装OpenGL -> 解析DXF直线
开发语言·c++
?!7141 小时前
数据结构之双链表
c语言·数据结构·c++
序属秋秋秋1 小时前
《数据结构初阶》【顺序栈 + 链式队列 + 循环队列】
c语言·数据结构·c++·笔记·算法
明月看潮生2 小时前
青少年编程与数学 02-018 C++数据结构与算法 26课题、数据压缩算法
c++·算法·青少年编程·编程与数学
花火QWQ3 小时前
CF1000E We Need More Bosses
数据结构·c++·算法
JANYI20189 小时前
C文件在C++平台编译时的注意事项
java·c语言·c++
freyazzr10 小时前
Leetcode刷题 | Day51_图论03_岛屿问题02
数据结构·c++·算法·leetcode·深度优先·图论