c语言版贪吃蛇(Pro Max版)附源代码
1 背景
贪吃蛇是一款经典的电子游戏,最早出现在20世纪70年代的街机游戏中。游戏的核心玩法是玩家控制一条蛇在有限的空间内移动,通过吃食物来增长身体长度,同时避免撞到墙壁、障碍物或自身。随着蛇的长度增加,游戏难度逐渐提升。
本实验通过C语言实现一个增强版的贪吃蛇游戏,加入以下功能:
-
多种食物:普通食物和特殊食物,特殊食物具有额外效果。
-
障碍物:随机生成的障碍物增加游戏难度。
-
加速功能:玩家可以消耗能量加速蛇的移动。
-
传送门:蛇可以通过传送门在地图中快速移动。
-
统计系统:记录玩家的游戏数据,包括得分、游戏时间和最长蛇长度等
2 实验技术
2.1开发环境
编程语言:C语言
开发工具:Visual Studio 2022
操作系统:Windows 11
依赖库:Windows API(用于控制台操作和音效)
2.2 关键技术
控制台操作:
使用 SetConsoleCursorPosition 控制光标位置。
使用 SetConsoleTextAttribute 设置文本颜色。
使用 Beep 函数播放音效。
双缓冲技术:通过清空控制台并重新绘制地图,避免画面闪烁。
随机数生成:使用 rand 函数生成随机位置,确保食物和障碍物的随机性。
数据结构:
使用结构体管理游戏对象(蛇、食物、传送门等)。
使用二维数组表示地图。
文件操作:使用 fopen、fwrite 和 fread 实现游戏状态的保存与加载。
3 实现细节
下面来详细介绍贪吃蛇游戏的实现细节,涵盖了游戏的核心逻辑、数据结构、功能模块以及关键算法。
3.1 游戏核心数据结构
游戏的核心数据结构包括蛇、食物、传送门、游戏状态和统计信息等。
1.1 蛇 (Snake)
结构体定义:
typedef struct {
Point body[WIDTH * HEIGHT]; // 蛇的身体坐标
int length; // 蛇的长度
int direction; // 当前移动方向
int speed; // 移动速度
int boost_available; // 加速能量
int is_boosting; // 是否正在加速
} Snake;
说明:
蛇的身体由一系列坐标点组成,body[0] 是蛇头,body[length-1] 是蛇尾。
蛇的移动通过更新 body 数组实现。
加速功能通过 is_boosting 和 boost_available 控制。
1.2 食物 (Food)
结构体定义:
typedef struct {
Point pos; // 食物位置
int value; // 食物分值
char type; // 食物类型(普通/特殊)
int lifetime; // 特殊食物的存在时间
int is_special; // 是否为特殊食物
} Food;
说明:
普通食物 (*) 分值为 10,特殊食物 (#) 分值为 20。
特殊食物有倒计时 (lifetime),超时后消失。
1.3 传送门 (Portal)
结构体定义:
typedef struct {
Point pos1; // 传送门入口
Point pos2; // 传送门出口
int active; // 是否激活
} Portal;
说明:蛇头进入传送门后,从另一个传送门出口出现。
1.4 游戏状态 (GameState)
结构体定义:
typedef struct {
int score; // 当前得分
int high_score; // 最高得分
int level; // 当前等级
int is_running; // 游戏是否运行
int is_paused; // 游戏是否暂停
time_t start_time; // 游戏开始时间
Difficulty difficulty; // 游戏难度
int obstacles_count; // 障碍物数量
int power_ups; // 特殊道具数量
int portal_active; // 传送门是否激活
} GameState;
说明:管理游戏的运行状态、得分、等级、难度等信息。
1.5 统计信息 (Statistics)
结构体定义:
typedef struct {
int games_played; // 总游戏次数
int total_score; // 总得分
int longest_snake; // 最长蛇长度
time_t total_play_time; // 总游戏时间
float average_score; // 平均得分
int highest_level; // 最高等级
int total_food_eaten; // 总食物数量
} Statistics;
说明:记录玩家的游戏数据,用于统计和展示。
3.2游戏整体框架
3.3模块划分
(1)游戏核心逻辑模块
组件 | 功能描述 | 重要性 |
Snake | 蛇的属性与行为管理 | 核心 |
Food | 食物生成与状态管理 | 核心 |
GameState | 游戏状态控制 | 重要 |
Score | 得分系统管理 | 次要 |
主要功能:
维护游戏核心数据结构
处理游戏逻辑
管理游戏状态转换
控制得分计算
(2)显示控制模块
组件 | 功能描述 | 重要性 |
width/height | 显示区域尺寸控制 | 基础 |
buffer | 显示缓冲区管理 | 核心 |
colors | 颜色方案控制 | 优化 |
主要功能:
管理显示区域大小
控制显示缓冲
处理颜色渲染
优化显示效果
(3)输入控制模块
组件 | 功能描述 | 重要性 |
device | 输入设备管理 | 核心 |
state | 输入状态维护 | 重要 |
callback | 输入响应处理 | 核心 |
主要功能:
处理用户输入
维护输入状态
执行回调函数
管理输入设备
3.4核心算法
(1) 蛇身移动算法
算法具体步骤如下:
1.保存尾部:
获取蛇身体最后一个元素(即尾部)的坐标,并将其存储在变量tail中。
2.身体移动:
从蛇的尾部开始,即数组body的最后一个元素,向前遍历至头部(即数组的第一个元素)。
在遍历过程中,每个元素的坐标被更新为前一个元素的坐标。这样,蛇的身体就向前移动了一个单位。
3.头部移动:
根据蛇当前的方向(dir),更新蛇头的坐标:
如果方向是UP,则蛇头的y坐标减1(向上移动)。
如果方向是DOWN,则蛇头的y坐标加1(向下移动)。
如果方向是LEFT,则蛇头的x坐标减1(向左移动)。
如果方向是RIGHT,则蛇头的x坐标加1(向右移动)。
(2)碰撞检测算法
算法具体步骤如下:
1.获取蛇头位置:从snake结构体中取出数组的第一个元素,这个元素表示蛇头的位置,并将其存储在变量head中。
2.检查边界碰撞:
判断蛇头的x坐标是否小于0或者大于等于游戏区域的宽度WIDTH。
判断蛇头的y坐标是否小于0或者大于等于游戏区域的高度HEIGHT。
如果以上任一条件成立,说明蛇头已经碰撞到边界,函数返回true表示发生碰撞。
3.检查自身碰撞:
从数组的第二个元素开始遍历(索引为1,因为第一个元素是蛇头,不需要与自己比较),直到蛇的长度snake->length。
在循环中,判断当前蛇身的x坐标和y坐标是否与蛇头的坐标相同。
如果找到任何一个蛇身部分的坐标与蛇头坐标相同,说明蛇头碰撞到了自己的身体,函数返回true表示发生碰撞。
4.如果以上两种碰撞情况都没有发生,则函数返回false,表示没有发生碰撞。
(3)双缓冲池技术
-
使用双缓冲技术避免画面闪烁。
-
通过
SetConsoleCursorPosition
和SetConsoleTextAttribute
控制控制台光标和颜色。
优化方法 | 实现要点 | 预期效果 |
增量更新 | 仅更新变化部分 | 提升刷新率 |
双缓冲 | 防止画面闪烁 | 平滑显示 |
局部刷新 | 减少刷新区域 | 降低开销 |
3.5游戏总体实现步骤
4 游戏展示
(1) 游戏主页面
(2)开始新游戏
(3)保存游戏状态
(4)加载之前保存的游戏状态
(5)选择游戏难度
(6)游戏说明
5 源代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string.h>
#include <ctype.h> // 为tolower函数
//@author:小梁不秃捏
// link:https://blog.csdn.net/m0_73804764?spm=1000.2115.3001.5343
// 替代 usleep 函数
void my_sleep(unsigned long microseconds) {
Sleep(microseconds / 1000);
}
// 游戏配置
#define WIDTH 50
#define HEIGHT 25
#define STUDENT_ID "2022212396"
#define MAX_SPEED 50
#define MIN_SPEED 200
// 游戏元素
#define SNAKE_HEAD 'O'
#define SNAKE_BODY 'o'
#define NORMAL_FOOD '*'
#define SPECIAL_FOOD '#'
#define WALL '#'
#define OBSTACLE 'X'
#define EMPTY ' '
#define PORTAL '@'
// 方向枚举
enum Direction {
UP,
DOWN,
LEFT,
RIGHT
};
// 控制键
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
#define KEY_PAUSE 'p'
#define KEY_SAVE 'v'
#define KEY_BOOST 'b'
// 颜色定义
#define COLOR_RED FOREGROUND_RED | FOREGROUND_INTENSITY
#define COLOR_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define COLOR_BLUE FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define COLOR_PURPLE FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_CYAN FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
// 游戏难度
typedef enum {
EASY = 1,
MEDIUM = 2,
HARD = 3
} Difficulty;
// 基础结构体
typedef struct {
int x, y;
} Point;
typedef struct {
Point body[WIDTH * HEIGHT];
int length;
int direction;
int speed;
int boost_available;
int is_boosting;
} Snake;
typedef struct {
Point pos;
int value;
char type;
int lifetime;
int is_special;
} Food;
typedef struct {
Point pos1;
Point pos2;
int active;
} Portal;
typedef struct {
int score;
int high_score;
int level;
int is_running;
int is_paused;
time_t start_time;
Difficulty difficulty;
int obstacles_count;
int power_ups;
int portal_active;
} GameState;
typedef struct {
int games_played;
int total_score;
int longest_snake;
time_t total_play_time;
float average_score;
int highest_level;
int total_food_eaten;
} Statistics;
// 全局变量
Snake snake;
Food food;
Portal portal;
GameState game;
Statistics stats;
char map[HEIGHT][WIDTH];
HANDLE hConsole;
char obstacle_map[HEIGHT][WIDTH] = { 0 }; // 用于保存障碍物位置
// 初始化双缓冲
void init_double_buffer() {
// 获取标准输出句柄
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// 设置控制台窗口和缓冲区大小
COORD coord = { WIDTH * 2 + 30, HEIGHT + 15 };
SMALL_RECT rect = { 0, 0, WIDTH * 2 + 29, HEIGHT + 14 };
SetConsoleScreenBufferSize(hConsole, coord);
SetConsoleWindowInfo(hConsole, TRUE, &rect);
// 隐藏光标
CONSOLE_CURSOR_INFO info = { 100, FALSE };
SetConsoleCursorInfo(hConsole, &info);
}
// 颜色控制函数
void set_color(int color) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
// 终端控制函数
void init_terminal(void) {
// 设置控制台窗口大小
char cmd[100];
sprintf_s(cmd, "mode con cols=%d lines=%d", WIDTH * 2 + 30, HEIGHT + 15);
system(cmd);
// 隐藏光标
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info;
info.dwSize = 100;
info.bVisible = FALSE;
SetConsoleCursorInfo(consoleHandle, &info);
}
void reset_terminal(void) {
system("cls");
}
void clear_screen(void) {
system("cls");
}
// 声音效果
void play_effect(int type) {
switch (type) {
case 1: // 吃到普通食物
Beep(800, 50);
break;
case 2: // 吃到特殊食物
Beep(1000, 50);
Beep(1200, 50);
Beep(1500, 50);
Beep(2000, 50);
break;
case 3: // 游戏结束
Beep(200, 200);
Beep(150, 200);
break;
}
}
// 动画效果
void show_animation(const char* text) {
clear_screen();
printf("\n\n\n");
set_color(COLOR_YELLOW);
for (int i = 0; text[i] != '\0'; i++) {
printf("%c", text[i]);
Sleep(50);
fflush(stdout);
}
set_color(COLOR_WHITE);
Sleep(1000);
}
// 改进的随机位置生成
Point get_random_position() {
Point pos;
int attempts = 0;
const int MAX_ATTEMPTS = 100;
do {
pos.x = rand() % (WIDTH - 2) + 1;
pos.y = rand() % (HEIGHT - 2) + 1;
attempts++;
if (attempts >= MAX_ATTEMPTS) {
for (int i = 1; i < HEIGHT - 1; i++) {
for (int j = 1; j < WIDTH - 1; j++) {
if (map[i][j] == EMPTY) {
pos.x = j;
pos.y = i;
return pos;
}
}
}
}
} while (map[pos.y][pos.x] != EMPTY);
return pos;
}
// 生成传送门
void generate_portal() {
if (!game.portal_active) {
portal.pos1 = get_random_position();
portal.pos2 = get_random_position();
map[portal.pos1.y][portal.pos1.x] = PORTAL;
map[portal.pos2.y][portal.pos2.x] = PORTAL;
portal.active = 1;
game.portal_active = 1;
}
}
// 保存游戏状态
void save_game_state() {
FILE* file;
if (fopen_s(&file, "snake_save.dat", "wb") == 0) {
fwrite(&snake, sizeof(Snake), 1, file);
fwrite(&food, sizeof(Food), 1, file);
fwrite(&portal, sizeof(Portal), 1, file);
fwrite(&game, sizeof(GameState), 1, file);
fwrite(map, sizeof(map), 1, file);
fclose(file);
show_animation("游戏已保存!");
}
}
// 加载游戏状态
void load_game_state() {
FILE* file;
if (fopen_s(&file, "snake_save.dat", "rb") == 0) {
fread(&snake, sizeof(Snake), 1, file);
fread(&food, sizeof(Food), 1, file);
fread(&portal, sizeof(Portal), 1, file);
fread(&game, sizeof(GameState), 1, file);
fread(map, sizeof(map), 1, file);
fclose(file);
show_animation("游戏已加载!");
}
else {
show_animation("没有找到存档!");
}
}
// 设置游戏难度
void set_difficulty(int level) {
switch (level) {
case EASY:
snake.speed = 200; // 较慢
game.obstacles_count = 5;
break;
case MEDIUM:
snake.speed = 150; // 中等
game.obstacles_count = 10;
break;
case HARD:
snake.speed = 100; // 较快
game.obstacles_count = 15;
break;
default:
snake.speed = 200; // 默认较慢
game.obstacles_count = 5;
}
game.difficulty = (Difficulty)level;
}
// 修改generate_food函数
void generate_food() {
food.pos = get_random_position();
// 确保食物不会生成在蛇身上或障碍物上
int valid_position = 0;
while (!valid_position) {
valid_position = 1;
// 检查是否在蛇身上
for (int i = 0; i < snake.length; i++) {
if (food.pos.x == snake.body[i].x && food.pos.y == snake.body[i].y) {
food.pos = get_random_position();
valid_position = 0;
break;
}
}
// 检查是否在障碍物上
if (map[food.pos.y][food.pos.x] == OBSTACLE) {
food.pos = get_random_position();
valid_position = 0;
continue;
}
}
// 设置食物类型和属性
food.is_special = (rand() % 10 == 0); // 10%的概率生成特殊食物
if (food.is_special) {
food.type = SPECIAL_FOOD;
food.value = 20;
food.lifetime = 50;
}
else {
food.type = NORMAL_FOOD;
food.value = 10;
food.lifetime = -1;
}
// 在地图上放置食物
map[food.pos.y][food.pos.x] = food.type;
}
// 生成障碍物
void generate_obstacles() {
for (int i = 0; i < game.obstacles_count; i++) {
Point pos = get_random_position();
map[pos.y][pos.x] = OBSTACLE;
}
}
// 初始化游戏
void init_game() {
// 清空地图和障碍物地图
memset(map, EMPTY, sizeof(map));
memset(obstacle_map, 0, sizeof(obstacle_map));
// 设置默认速度(如果没有设置难度)
if (snake.speed == 0) {
snake.speed = MIN_SPEED;
}
// 初始化边界
for (int i = 0; i < WIDTH; i++) {
map[0][i] = WALL;
map[HEIGHT - 1][i] = WALL;
}
for (int i = 0; i < HEIGHT; i++) {
map[i][0] = WALL;
map[i][WIDTH - 1] = WALL;
}
// 初始化蛇
snake.length = 3;
snake.body[0].x = WIDTH / 2;
snake.body[0].y = HEIGHT / 2;
snake.body[1].x = snake.body[0].x - 1;
snake.body[1].y = snake.body[0].y;
snake.body[2].x = snake.body[1].x - 1;
snake.body[2].y = snake.body[1].y;
snake.direction = RIGHT;
snake.boost_available = 100;
snake.is_boosting = 0;
// 在地图上放置蛇
map[snake.body[0].y][snake.body[0].x] = SNAKE_HEAD;
for (int i = 1; i < snake.length; i++) {
map[snake.body[i].y][snake.body[i].x] = SNAKE_BODY;
}
// 初始化游戏状态
game.score = 0;
game.level = 1;
game.is_running = 1;
game.is_paused = 0;
game.power_ups = 3;
game.portal_active = 0;
game.start_time = time(NULL);
// 生成初始食物和障碍物
// 生成障碍物时同时更新 obstacle_map
for (int i = 0; i < game.obstacles_count; i++) {
Point pos = get_random_position();
map[pos.y][pos.x] = OBSTACLE;
obstacle_map[pos.y][pos.x] = 1;
}
generate_food(); // 只生成一个食物
// 初始化传送门
portal.active = 0;
game.portal_active = 0; // 确保初始状态无传送门
}
// 更新分数
void update_score() {
game.score += food.value;
if (game.score > game.high_score) {
game.high_score = game.score;
}
// 每100分升一级
int new_level = game.score / 100 + 1;
if (new_level != game.level) {
game.level = new_level;
snake.speed = snake.speed > MAX_SPEED ? snake.speed - 10 : snake.speed;
show_animation("升级!");
}
}
// 更新统计信息
void update_statistics() {
stats.games_played++;
stats.total_score += game.score;
stats.average_score = (float)stats.total_score / stats.games_played;
if (snake.length > stats.longest_snake) {
stats.longest_snake = snake.length;
}
if (game.level > stats.highest_level) {
stats.highest_level = game.level;
}
stats.total_play_time += time(NULL) - game.start_time;
}
// 保存统计信息
void save_statistics() {
FILE* file;
if (fopen_s(&file, "snake_stats.dat", "wb") == 0) {
fwrite(&stats, sizeof(Statistics), 1, file);
fclose(file);
}
}
// 检查碰撞
int check_collision(int x, int y) {
// 检查是否撞墙
if (map[y][x] == WALL) return 1;
// 检查是否撞到障碍物
if (map[y][x] == OBSTACLE) return 1;
// 检查是否撞到自己(除了尾巴,因为尾巴会移动)
for (int i = 0; i < snake.length - 1; i++) {
if (snake.body[i].x == x && snake.body[i].y == y) {
return 1;
}
}
return 0;
}
// 在move_snake函数
void move_snake() {
int new_x = snake.body[0].x;
int new_y = snake.body[0].y;
switch (snake.direction) {
case UP: new_y--; break;
case DOWN: new_y++; break;
case LEFT: new_x--; break;
case RIGHT: new_x++; break;
}
// 处理加速能量衰减
if (snake.is_boosting && snake.boost_available > 0) {
snake.boost_available--;
if (snake.boost_available <= 0) {
snake.is_boosting = 0;
}
}
// 检查碰撞
if (check_collision(new_x, new_y)) {
game.is_running = 0;
play_effect(3);
return;
}
// 检查是否吃到食物
if (new_x == food.pos.x && new_y == food.pos.y) {
// 增加蛇的长度
snake.length++;
// 更新分数
update_score();
// 播放音效
play_effect(food.is_special ? 2 : 1);
// 如果是特殊食物,增加加速能量
if (food.is_special) {
snake.boost_available += 50;
}
// 先移动蛇身
for (int i = snake.length - 1; i > 0; i--) {
snake.body[i] = snake.body[i - 1];
}
// 更新蛇头位置
snake.body[0].x = new_x;
snake.body[0].y = new_y;
// 生成新的食物
generate_food();
}
else {
// 如果没有吃到食物,正常移动
// 移动蛇身
for (int i = snake.length - 1; i > 0; i--) {
snake.body[i] = snake.body[i - 1];
}
// 更新蛇头位置
snake.body[0].x = new_x;
snake.body[0].y = new_y;
}
// 更新地图
memset(map, EMPTY, sizeof(map));
// 重绘边界
for (int i = 0; i < WIDTH; i++) {
map[0][i] = WALL;
map[HEIGHT - 1][i] = WALL;
}
for (int i = 0; i < HEIGHT; i++) {
map[i][0] = WALL;
map[i][WIDTH - 1] = WALL;
}
// 重绘障碍物
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if (obstacle_map[i][j]) {
map[i][j] = OBSTACLE;
}
}
}
// 重绘蛇
map[snake.body[0].y][snake.body[0].x] = SNAKE_HEAD;
for (int i = 1; i < snake.length; i++) {
map[snake.body[i].y][snake.body[i].x] = SNAKE_BODY;
}
// 重绘食物
map[food.pos.y][food.pos.x] = food.type;
}
// 修改draw_game函数
void draw_game() {
// 移动光标到起始位置
COORD pos = { 0, 0 };
SetConsoleCursorPosition(hConsole, pos);
// 绘制游戏信息
SetConsoleTextAttribute(hConsole, COLOR_YELLOW);
printf("\n 得分: %d 最高分: %d 等级: %d 加速能量: %d%%\n",
game.score, game.high_score, game.level, snake.boost_available);
printf(" 难度: ");
switch (game.difficulty) {
case EASY: printf("简单"); break;
case MEDIUM: printf("中等"); break;
case HARD: printf("困难"); break;
}
printf(" 游戏时间: %d秒\n\n", (int)(time(NULL) - game.start_time));
// 绘制地图
for (int i = 0; i < HEIGHT; i++) {
printf(" ");
for (int j = 0; j < WIDTH; j++) {
switch (map[i][j]) {
case SNAKE_HEAD:
SetConsoleTextAttribute(hConsole, COLOR_GREEN);
printf("O ");
break;
case SNAKE_BODY:
SetConsoleTextAttribute(hConsole, COLOR_GREEN);
printf("o ");
break;
case NORMAL_FOOD:
SetConsoleTextAttribute(hConsole, COLOR_RED);
printf("* ");
break;
case SPECIAL_FOOD:
SetConsoleTextAttribute(hConsole, COLOR_PURPLE);
printf("# ");
break;
case OBSTACLE:
SetConsoleTextAttribute(hConsole, COLOR_RED);
printf("X ");
break;
case PORTAL:
SetConsoleTextAttribute(hConsole, COLOR_CYAN);
printf("@ ");
break;
default:
SetConsoleTextAttribute(hConsole, COLOR_WHITE);
printf(" ");
}
}
printf("\n");
}
// 绘制控制说明
SetConsoleTextAttribute(hConsole, COLOR_WHITE);
printf("\n 控制: WASD移动 P暂停 Q退出 V保存 B加速\n");
}
// 显示菜单
int show_menu() {
clear_screen();
set_color(COLOR_YELLOW);
printf("\n");
printf(" SSSSS N N AAA K K EEEEE\n");
printf(" S NN N A A K K E \n");
printf(" SSSSS N N N AAAAA KK EEEE \n");
printf(" S N NN A A K K E \n");
printf(" SSSSS N N A A K K EEEEE\n");
printf("\n\n");
printf(" ----------\n\n");
printf(" 小梁贪吃蛇(pro max版)\n");
printf(" 1. 新游戏\n");
printf(" 2. 加载游戏\n");
printf(" 3. 查看统计\n");
printf(" 4. 选择难度\n");
printf(" 5. 游戏说明\n");
printf(" 6. 退出\n\n");
printf(" 请选择: ");
set_color(COLOR_WHITE);
int choice;
scanf_s("%d", &choice);
return choice;
}
// 显示统计信息
void show_statistics() {
clear_screen();
set_color(COLOR_CYAN);
printf("\n\n");
printf(" 游戏统计\n");
printf(" --------\n\n");
printf(" 总游戏次数: %d\n", stats.games_played);
printf(" 总得分: %d\n", stats.total_score);
printf(" 平均得分: %.2f\n", stats.average_score);
printf(" 最长蛇长度: %d\n", stats.longest_snake);
printf(" 最高等级: %d\n", stats.highest_level);
printf(" 总游戏时间: %d分钟\n\n", (int)(stats.total_play_time / 60));
printf(" 按任意键返回...");
set_color(COLOR_WHITE);
_getch();
}
// 显示游戏说明
void show_instructions() {
clear_screen();
set_color(COLOR_CYAN);
printf("\n\n");
printf(" 游戏说明\n");
printf(" --------\n\n");
printf(" 控制方式:\n");
printf(" W - 向上移动\n");
printf(" S - 向下移动\n");
printf(" A - 向左移动\n");
printf(" D - 向右移动\n");
printf(" P - 暂停游戏\n");
printf(" Q - 退出游戏\n");
printf(" V - 保存游戏\n");
printf(" B - 开启/关闭加速\n\n");
printf(" 游戏规则:\n");
printf(" * - 普通食物,得分+10\n");
printf(" # - 特殊食物,得分+20,有特殊效果\n");
printf(" @ - 传送门,可传送到另一端\n");
printf(" X - 障碍物,碰到即死亡\n\n");
printf(" 特殊食物效果:\n");
printf(" 1. 增加加速能量\n");
printf(" 2. 生成传送门\n");
printf(" 3. 清除障碍物\n\n");
printf(" 按任意键返回...");
set_color(COLOR_WHITE);
_getch();
}
// 主函数
int main() {
srand((unsigned)time(NULL));
init_terminal();
init_double_buffer(); // 添加这行
while (1) {
int choice = show_menu();
switch (choice) {
case 1: // 新游戏
init_game();
while (game.is_running) {
if (!game.is_paused) {
move_snake();
draw_game();
// 特殊食物倒计时
if (food.is_special && food.lifetime > 0) {
food.lifetime--;
if (food.lifetime <= 0) {
generate_food();
}
}
// 控制游戏速度
int delay = snake.is_boosting ? snake.speed / 2 : snake.speed;
Sleep(delay);
}
// 处理输入
if (_kbhit()) {
char input = _getch();
switch (tolower(input)) { // 转换为小写以支持大小写
case 'w':
if (snake.direction != DOWN) snake.direction = UP;
break;
case 's':
if (snake.direction != UP) snake.direction = DOWN;
break;
case 'a':
if (snake.direction != RIGHT) snake.direction = LEFT;
break;
case 'd':
if (snake.direction != LEFT) snake.direction = RIGHT;
break;
case 'p':
game.is_paused = !game.is_paused;
break;
case 'q':
game.is_running = 0;
break;
case 'v':
save_game_state();
break;
case 'b':
if (snake.boost_available > 0) {
snake.is_boosting = !snake.is_boosting;
}
break;
}
}
}
update_statistics();
save_statistics();
break;
case 2: // 加载游戏
load_game_state();
break;
case 3: // 查看统计
show_statistics();
break;
case 4: // 选择难度
clear_screen();
printf("\n\n 选择难度(1-简单 2-中等 3-困难): ");
int level;
scanf_s("%d", &level);
set_difficulty(level);
break;
case 5: // 游戏说明
show_instructions();
break;
case 6: // 退出
CloseHandle(hConsole);
reset_terminal();
return 0;
}
}
return 0;
}