C语言基础:8.2项目2:控制台贪吃蛇游戏

控制台贪吃蛇游戏完整实现

一、游戏核心架构

1. 数据结构设计

typedef struct SnakeNode {
    int x;
    int y;
    struct SnakeNode* next;
} SnakeNode;

typedef struct {
    SnakeNode* head;
    SnakeNode* tail;
    int dx;  // X方向增量
    int dy;  // Y方向增量
    int food_x;
    int food_y;
    int score;
    int game_over;
} GameState;

2. 游戏初始化

void init_game(GameState* game) {
    // 创建初始蛇身(3节)
    SnakeNode* node1 = create_node(10, 10);
    SnakeNode* node2 = create_node(11, 10);
    SnakeNode* node3 = create_node(12, 10);
  
    node1->next = node2;
    node2->next = node3;
  
    game->head = node1;
    game->tail = node3;
    game->dx = 1;  // 初始向右移动
    game->dy = 0;
    game->score = 0;
    game->game_over = 0;
  
    generate_food(game);
}

SnakeNode* create_node(int x, int y) {
    SnakeNode* node = malloc(sizeof(SnakeNode));
    node->x = x;
    node->y = y;
    node->next = NULL;
    return node;
}

二、游戏循环实现

1. 主循环逻辑

void game_loop() {
    GameState game;
    init_game(&game);
  
    while (!game.game_over) {
        handle_input(&game);
        update_game(&game);
        render(&game);
        usleep(100000); // 控制游戏速度(100ms)
    }
  
    show_game_over(&game);
    free_resources(&game);
}

2. 运动更新逻辑

void update_game(GameState* game) {
    // 计算新头部位置
    int new_x = game->head->x + game->dx;
    int new_y = game->head->y + game->dy;
  
    // 碰撞检测
    if (check_collision(game, new_x, new_y)) {
        game->game_over = 1;
        return;
    }
  
    // 创建新头部
    SnakeNode* new_head = create_node(new_x, new_y);
    new_head->next = game->head;
    game->head = new_head;
  
    // 检查是否吃到食物
    if (new_x == game->food_x && new_y == game->food_y) {
        game->score += 10;
        generate_food(game);
    } else {
        // 移除尾部节点
        SnakeNode* prev = game->head;
        while (prev->next != game->tail) prev = prev->next;
        free(game->tail);
        prev->next = NULL;
        game->tail = prev;
    }
}

三、关键功能实现

1. 跨平台输入处理

// 通用输入处理接口
#ifdef _WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#endif

void handle_input(GameState* game) {
    int key = getch_nonblock();
  
    switch(key) {
        case 'w': case 'W': case KEY_UP:
            if (game->dy != 1) { game->dx = 0; game->dy = -1; }
            break;
        case 's': case 'S': case KEY_DOWN:
            if (game->dy != -1) { game->dx = 0; game->dy = 1; }
            break;
        case 'a': case 'A': case KEY_LEFT:
            if (game->dx != 1) { game->dx = -1; game->dy = 0; }
            break;
        case 'd': case 'D': case KEY_RIGHT:
            if (game->dx != -1) { game->dx = 1; game->dy = 0; }
            break;
        case 'q': case 'Q':
            game->game_over = 1;
            break;
    }
}

// 非阻塞输入实现
int getch_nonblock() {
#ifdef _WIN32
    if (_kbhit()) return _getch();
#else
    struct termios oldt, newt;
    int ch;
  
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  
    return ch;
#endif
    return -1;
}

2. 碰撞检测系统

int check_collision(GameState* game, int x, int y) {
    // 边界检测(假设游戏区域80x24)
    if (x < 0 || x >= 80 || y < 0 || y >= 24)
        return 1;
  
    // 自碰撞检测
    SnakeNode* current = game->head;
    while (current != NULL) {
        if (current != game->head && current->x == x && current->y == y)
            return 1;
        current = current->next;
    }
  
    return 0;
}

void generate_food(GameState* game) {
    do {
        game->food_x = rand() % 80;
        game->food_y = rand() % 24;
    } while (check_collision(game, game->food_x, game->food_y));
}

四、图形渲染模块

1. 跨平台绘制实现

void render(GameState* game) {
#ifdef _WIN32
    system("cls");
#else
    printf("\033[2J\033[H"); // 清屏
#endif

    // 绘制边界
    for (int x = 0; x < 80; x++) printf("#");
    printf("\n");
  
    for (int y = 0; y < 24; y++) {
        printf("#");
        for (int x = 1; x < 79; x++) {
            if (x == game->food_x && y == game->food_y)
                printf("F");
            else if (is_snake_body(game, x, y))
                printf("O");
            else
                printf(" ");
        }
        printf("#\n");
    }
  
    for (int x = 0; x < 80; x++) printf("#");
    printf("\nScore: %d\n", game->score);
}

int is_snake_body(GameState* game, int x, int y) {
    SnakeNode* current = game->head;
    while (current != NULL) {
        if (current->x == x && current->y == y)
            return 1;
        current = current->next;
    }
    return 0;
}

五、扩展功能实现

1. 难度分级系统

typedef struct {
    int speed;       // 更新间隔(ms)
    int food_score;  // 每个食物得分
    int wall_collision; // 是否开启墙碰撞
} Difficulty;

const Difficulty levels[] = {
    {150, 10, 1},   // 简单模式
    {100, 20, 1},    // 普通模式
    {80, 30, 0}     // 困难模式(可穿墙)
};

void set_difficulty(GameState* game, int level) {
    game->speed = levels[level].speed;
    game->food_score = levels[level].food_score;
    game->wall_collision = levels[level].wall_collision;
}

2. 存档功能

void save_game(GameState* game, const char* filename) {
    FILE* fp = fopen(filename, "wb");
    if (!fp) return;
  
    // 写入游戏状态
    fwrite(&game->dx, sizeof(int), 1, fp);
    fwrite(&game->dy, sizeof(int), 1, fp);
    fwrite(&game->score, sizeof(int), 1, fp);
  
    // 写入蛇身数据
    SnakeNode* current = game->head;
    while (current != NULL) {
        fwrite(current, sizeof(SnakeNode), 1, fp);
        current = current->next;
    }
  
    fclose(fp);
}

void load_game(GameState* game, const char* filename) {
    // 实现略,需要处理链表重建
}

编译与运行指南

  1. Linux/macOS 编译命令:

    gcc snake.c -o snake -lncurses
    ./snake
    
  2. Windows 编译命令(使用MinGW):

    gcc snake.c -o snake.exe -lconio
    snake.exe
    

核心玩法

  • WASD/方向键控制方向
  • Q键退出游戏
  • 吃到食物(F)增长身体
  • 碰撞墙壁或自身游戏结束

性能优化点

  1. 使用双向链表提升遍历效率
  2. 空间换时间:使用二维数组记录蛇身位置
  3. 分帧渲染减少闪烁
  4. 预分配节点内存池

扩展方向

  1. 添加不同皮肤支持
  2. 实现网络对战模式
  3. 添加道具系统(加速、护盾等)
  4. 支持关卡地图编辑
  5. 添加成就系统
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵鑫亿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值