项目:贪吃蛇游戏¶
项目介绍¶
使用 C 语言在 Windows 控制台中实现经典的贪吃蛇游戏,通过键盘控制蛇的移动,吃到食物增长身体,撞墙或撞自身则游戏结束。
核心功能¶
- WASD / 方向键控制蛇的移动
- 食物随机生成
- 碰撞检测(墙壁 / 自身)
- 实时计分显示
- 游戏结束判定与提示
涉及知识点¶
| 知识点 | 用途 |
|---|---|
| 二维数组 | 表示游戏地图 |
| 循环 | 主游戏循环 |
| 条件判断 | 碰撞检测 |
| 控制台函数 | 隐藏光标、清屏、定位光标 |
| 随机数 | 食物位置生成 |
| 结构体 | 表示蛇身节点 |
完整代码¶
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
// 地图尺寸
#define WIDTH 20
#define HEIGHT 20
// 游戏状态
int game_over = 0;
int score = 0;
// 蛇的坐标结构
typedef struct {
int x;
int y;
} Point;
// 蛇(用数组模拟)
Point snake[WIDTH * HEIGHT];
int snake_len = 3;
// 食物坐标
Point food;
// 移动方向
enum Direction { UP, DOWN, LEFT, RIGHT };
enum Direction dir = RIGHT;
// 隐藏控制台光标
void hide_cursor() {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info;
info.dwSize = 100;
info.bVisible = FALSE;
SetConsoleCursorInfo(handle, &info);
}
// 定位光标位置
void gotoxy(int x, int y) {
COORD pos = { x * 2, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
// 初始化游戏
void init_game() {
// 初始蛇:水平三条
snake[0].x = 5; snake[0].y = HEIGHT / 2;
snake[1].x = 4; snake[1].y = HEIGHT / 2;
snake[2].x = 3; snake[2].y = HEIGHT / 2;
// 随机生成食物
srand((unsigned)time(NULL));
food.x = rand() % (WIDTH - 2) + 1;
food.y = rand() % (HEIGHT - 2) + 1;
hide_cursor();
}
// 绘制地图和蛇
void draw() {
system("cls");
// 绘制上边界
for (int i = 0; i < WIDTH; i++)
printf("█");
printf("\n");
// 绘制中间区域
for (int y = 0; y < HEIGHT; y++) {
printf("█"); // 左边界
for (int x = 0; x < WIDTH; x++) {
int is_snake = 0;
for (int i = 0; i < snake_len; i++) {
if (snake[i].x == x && snake[i].y == y) {
is_snake = 1;
break;
}
}
if (is_snake)
printf("■");
else if (food.x == x && food.y == y)
printf("★");
else
printf(" ");
}
printf("█\n"); // 右边界
}
// 绘制下边界
for (int i = 0; i < WIDTH; i++)
printf("█");
printf("\n");
printf("得分:%d\n", score);
printf("按 WASD 控制方向,按 Q 退出\n");
}
// 处理键盘输入
void input() {
if (_kbhit()) {
switch (_getch()) {
case 'w': case 'W': if (dir != DOWN) dir = UP; break;
case 's': case 'S': if (dir != UP) dir = DOWN; break;
case 'a': case 'A': if (dir != RIGHT) dir = LEFT; break;
case 'd': case 'D': if (dir != LEFT) dir = RIGHT; break;
case 'q': case 'Q': game_over = 1; break;
}
}
}
// 移动蛇
void move_snake() {
// 计算新蛇头坐标
Point new_head = snake[0];
switch (dir) {
case UP: new_head.y--; break;
case DOWN: new_head.y++; break;
case LEFT: new_head.x--; break;
case RIGHT: new_head.x++; break;
}
// 碰撞检测:墙壁
if (new_head.x < 0 || new_head.x >= WIDTH ||
new_head.y < 0 || new_head.y >= HEIGHT) {
game_over = 1;
return;
}
// 碰撞检测:自身
for (int i = 0; i < snake_len; i++) {
if (snake[i].x == new_head.x && snake[i].y == new_head.y) {
game_over = 1;
return;
}
}
// 判断是否吃到食物
int ate_food = (new_head.x == food.x && new_head.y == food.y);
// 移动蛇:从尾部向前移动
for (int i = snake_len - 1; i > 0; i--)
snake[i] = snake[i - 1];
snake[0] = new_head;
// 如果吃到食物,在尾部增加一节
if (ate_food) {
snake[snake_len] = snake[snake_len - 1]; // 尾部复制
snake_len++;
score += 10;
// 生成新食物
int valid = 0;
while (!valid) {
food.x = rand() % (WIDTH - 2) + 1;
food.y = rand() % (HEIGHT - 2) + 1;
valid = 1;
for (int i = 0; i < snake_len; i++) {
if (snake[i].x == food.x && snake[i].y == food.y) {
valid = 0;
break;
}
}
}
}
}
// 主函数
int main() {
init_game();
while (!game_over) {
draw();
input();
move_snake();
Sleep(150); // 控制游戏速度(毫秒)
}
system("cls");
printf("════════════════════════\n");
printf(" 游戏结束!\n");
printf(" 最终得分:%d\n", score);
printf("════════════════════════\n");
printf("按任意键退出...\n");
_getch();
return 0;
}
核心算法解析¶
蛇的移动逻辑¶
蛇的身体用数组 snake[] 存储,snake[0] 为蛇头。每次移动时:
1. 根据方向计算新蛇头坐标
2. 从尾部开始,每个节点向前移动一位(snake[i] = snake[i-1])
3. 将新蛇头设为 snake[0]
碰撞检测¶
- 墙壁碰撞:检查新蛇头坐标是否超出地图边界
- 自身碰撞:遍历蛇身数组,检查新蛇头是否与身体重合
食物生成¶
食物不能生成在蛇身上,因此需要循环检查位置是否被蛇占据。
扩展挑战¶
- 增加难度选择:游戏开始前让玩家选择速度(简单/普通/困难)
- 增加障碍物:地图中随机生成障碍物
- 记录最高分:将最高分保存到文件中,每次游戏开始时读取
- 穿墙模式:蛇从一端穿出,从另一端出现
- 彩色界面:使用控制台颜色函数美化界面
- 暂停功能:按 P 键暂停/继续游戏