【附C语言源码】从零实现命令行贪吃蛇游戏
项目背景
贪吃蛇是一款经典的休闲游戏,其核心玩法简单但极具挑战性。作为一名开发者,用C语言从零实现一个命令行版贪吃蛇,不仅能加深对基础数据结构的理解,还能锻炼逻辑思维和代码组织能力。本文将详细介绍如何实现一个功能完整、交互流畅的命令行贪吃蛇游戏。
技术选型
考虑到命令行环境的特性和Windows平台的兼容性,本项目采用以下技术方案:
- 开发语言: C语言(标准C99)
- 平台适配: Windows API(控制台控制)
- 输入处理 :
_kbhit()+_getch()实现非阻塞输入 - 界面渲染: Windows控制台字符输出
核心数据结构设计
方向枚举
c
enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN };
使用枚举类型替代魔法数字,提高代码可读性和可维护性。
坐标点结构
c
typedef struct {
int x;
int y;
} Point;
简洁的二维坐标表示,用于定位蛇身和食物。
蛇结构体
c
typedef struct {
Point body[GAME_WIDTH*GAME_HEIGHT];
int length;
enum Direction dir;
enum Direction nextDir;
} Snake;
设计要点:
- 使用数组存储蛇身坐标,最大长度为游戏区域总面积
nextDir字段用于处理输入缓冲,防止蛇瞬间反向- 采用头插法管理蛇身移动,尾部自动跟进
游戏状态管理
c
typedef struct {
Snake snake;
Food food;
bool gameOver;
int score;
int speed;
int highScore;
int oldTailX;
int oldTailY;
bool boost;
} Game;
集中管理游戏状态,便于函数间传递和维护。
关键功能实现
1. 非阻塞输入处理
c
void processInput(Game *game) {
if (_kbhit()) {
int key = _getch();
// 方向键与WASD双支持
// 防反向逻辑
}
}
技术亮点:
- 使用
_kbhit()检测按键状态,实现非阻塞输入 - 支持方向键和WASD两种控制方式
- 防反向机制避免蛇自撞
2. 蛇身移动算法
c
void updateGame(Game *game) {
// 方向切换
game->snake.dir = game->snake.nextDir;
// 记录旧尾位置(用于擦除)
game->oldTailX = game->snake.body[game->snake.length - 1].x;
game->oldTailY = game->snake.body[game->snake.length - 1].y;
// 蛇身移动:从尾部开始依次覆盖
for (int i = game->snake.length - 1; i > 0; i--) {
game->snake.body[i] = game->snake.body[i - 1];
}
// 蛇头移动
switch (game->snake.dir) {
case LEFT: game->snake.body[0].x--; break;
case RIGHT: game->snake.body[0].x++; break;
case UP: game->snake.body[0].y--; break;
case DOWN: game->snake.body[0].y++; break;
}
}
算法设计思路:
- 先记录旧尾坐标用于后续擦除
- 从尾部向前覆盖,实现O(n)复杂度的移动
- 蛇头单独处理,根据方向更新坐标
3. 食物生成机制
c
void generateFood(Game *game) {
bool valid;
do {
valid = true;
game->food.x = (rand() % GAME_WIDTH) + 1;
game->food.y = (rand() % GAME_HEIGHT) + 1;
// 碰撞检测:确保不与蛇身重叠
for (int i = 0; i < game->snake.length; i++) {
if (game->food.x == game->snake.body[i].x &&
game->food.y == game->snake.body[i].y) {
valid = false;
break;
}
}
} while (!valid);
}
关键技术点:
- 使用
do-while循环确保生成有效位置 - 随机数范围限制在游戏区域内
- 碰撞检测避免食物出现在蛇身上
4. 加速功能实现
c
void checkBoost(Game *game) {
if (GetAsyncKeyState(VK_UP) & 0x8000 ||
GetAsyncKeyState(VK_DOWN) & 0x8000 ||
GetAsyncKeyState('W') & 0x8000 ||
GetAsyncKeyState('S') & 0x8000) {
game->boost = true;
} else {
game->boost = false;
}
}
使用GetAsyncKeyState()检测按键长按状态,实现流畅的加速体验。
5. 持久化存储
c
void loadHighScore(Game *game) {
FILE* file = fopen("snake_highscore.txt", "r");
if (file != NULL) {
fscanf(file, "%d", &((*game).highScore));
fclose(file);
} else {
(*game).highScore = 0;
}
}
简单的文件读写实现最高分持久化。
游戏循环设计
c
while (!game.gameOver) {
processInput(&game);
updateGame(&game);
if (!game.gameOver) {
drawGame(&game);
drawInfo(&game);
}
checkBoost(&game);
int sleepTime = game.boost ? (game.speed / 2) : game.speed;
if (sleepTime < 10) sleepTime = 10;
Sleep(sleepTime);
}
主循环流程:
- 输入处理 → 2. 游戏逻辑更新 → 3. 画面渲染 → 4. 加速检测 → 5. 帧率控制
界面优化
彩色输出
c
void setColor(int color) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
通过Windows API实现彩色字符输出,提升视觉体验。
光标控制
c
void hideCursor() {
CONSOLE_CURSOR_INFO cursor_info = {100, FALSE};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
隐藏控制台光标,避免闪烁影响游戏体验。
编译与运行
bash
# 编译命令
gcc 贪吃蛇(命令行版).c -o snake.exe
# 直接运行
snake.exe
已编译的可执行文件a.exe可直接运行。
游戏开始界面:

游戏中的场景:

游戏结束界面 :

扩展功能建议
- 难度递增系统:随时间增加游戏速度
- 多种游戏模式:限时模式、生存模式等
- 音效系统:添加吃食物和死亡音效
- 多人对战:分屏双人模式
- 障碍物系统:增加游戏难度
总结
本项目展示了如何用C语言实现一个完整的贪吃蛇游戏。核心技术包括:
- 数据结构设计(结构体、枚举)
- 非阻塞输入处理
- 游戏循环架构
- Windows控制台API应用
- 文件持久化
代码结构清晰,注释详尽,适合作为C语言学习和游戏开发入门的参考项目。
⚠️源码地址:https://github.com/anjuxi/Snake_game-command_line_version