一、前言:为什么要用C++写游戏?
"都2024年了还用C++搞游戏?Unity不香吗?"------如果你这么想,咱们得聊聊。用C++搓游戏就像手动挡飙车:虐,但爽!它能让你真正理解内存管理、帧率控制、算法优化 这些底层逻辑。今天咱们不用任何游戏引擎,就用最朴素的cout
和while循环
,在控制台里搞个能玩的贪吃蛇!(温馨提示:本文代码在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用户:
- 用Visual Studio新建空项目
- 把代码粘贴到main.cpp
- 按F5运行(如果报错,检查是否勾选"使用多字节字符集")
Linux/macOS用户:
- 安装ncurses库:
sudo apt install libncurses5-dev
- 把
conio.h
相关代码替换成ncurses实现(需要可以留言,我另写教程)
五、功能扩展指南(装X必备)
- 增加难度等级:随着分数提升缩短Sleep时间
- 存档功能:把snake vector写入文件
- 双人对战:用WASD和方向键控制两条蛇
- 图形界面:集成SDL2库替换cout渲染
六、避雷指南(泪目了)
- 别在update里调用draw:会导致闪烁,帧率不稳
- 蛇身移动顺序:先插头再删尾,顺序反了会抽搐
- 随机数陷阱:不用srand(time(nullptr))会导致每次食物位置相同
- 撞墙检测边界:WIDTH-1和HEIGHT-1是重点,直接写WIDTH等着看蛇穿墙
七、结语
虽然这个控制台版贪吃蛇简陋得像个出土文物,但它包含了游戏循环、状态管理、输入处理这些核心概念。下次咱们可以试试用SDL2搞个带画面的版本------到时候你就能理直气壮地把这个代码贴到GitHub,标题写上"3A大作早期开发版本"了(手动狗头)。
有问题欢迎拍砖,代码要是跑不起来... 肯定是你键盘的问题(逃)