当前位置: 首页 > article >正文

c语言版贪吃蛇(Pro Max版)附源代码

1 背景

        贪吃蛇是一款经典的电子游戏,最早出现在20世纪70年代的街机游戏中。游戏的核心玩法是玩家控制一条蛇在有限的空间内移动,通过吃食物来增长身体长度,同时避免撞到墙壁、障碍物或自身。随着蛇的长度增加,游戏难度逐渐提升。

                                

本实验通过C语言实现一个增强版的贪吃蛇游戏,加入以下功能:

  1. 多种食物:普通食物和特殊食物,特殊食物具有额外效果。

  2. 障碍物:随机生成的障碍物增加游戏难度。

  3. 加速功能:玩家可以消耗能量加速蛇的移动。

  4. 传送门:蛇可以通过传送门在地图中快速移动。

  5. 统计系统:记录玩家的游戏数据,包括得分、游戏时间和最长蛇长度等


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;
}


http://www.kler.cn/a/522197.html

相关文章:

  • 使用kitty terminal遇到的‘xterm-kitty‘: unknown terminal type.
  • Linux线程安全
  • 第05章 11 动量剖面可视化代码一则
  • 洛谷U525322 优美区间
  • Hugging Face 推出最小体积多模态模型,浏览器运行成为现实!
  • SCRM在企业私域流量与客户管理中的变革之路探索
  • 题解 信息学奥赛一本通/AcWing 1118 分成互质组 DFS C++
  • 010 mybatis-PageHelper分页插件
  • 精通PCIe技术:协议解析与UVM验证实战
  • 大数据学习之SCALA分布式语言三
  • POWER SCHEDULER:一种与批次大小和token数量无关的学习率调度器
  • Mac Electron 应用签名(signature)和公证(notarization)
  • Mybatis初步了解
  • RU 19.26安装(手工安装各个补丁)
  • wxPython中wx.ListCtrl用法(四)
  • 66-《虞美人》
  • 从ai产品推荐到利用cursor快速掌握一个开源项目再到langchain手搓一个Text2Sql agent
  • 4.scala默认参数值
  • YOLO目标检测4
  • C#面试常考随笔6:ArrayList和 List的主要区别?
  • deepseek R1的确不错,特别是深度思考模式
  • excel如何查找一个表的数据在另外一个表是否存在
  • clean code阅读笔记——如何命名?
  • Nacos深度解析:构建高效微服务架构的利器
  • Python3 【高阶函数】项目实战:5 个学习案例
  • linux网络 | TCP可靠性策略之连接管理、滑动窗口、拥塞控制