You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言链表实现贪吃蛇:节点无法跟随前一节点问题求助

贪吃蛇节点跟随问题的解决方案

问题根源

你的代码里蛇身移动逻辑完全错误:每次移动头部后,两次遍历蛇身节点直接覆盖位置还额外加偏移,导致所有节点瞬间对齐头部,没有保留前一帧的位置信息,自然无法形成蛇形弯曲效果。

正确的蛇身移动逻辑应该是:

  • 先记录头部的旧位置
  • 从蛇尾开始,每个节点依次移动到前一个节点的旧位置
  • 最后再移动头部到新位置

具体修改步骤

  1. 重构移动逻辑:删除每个方向分支里重复的蛇身遍历代码,换成从尾部向前更新位置的逻辑
  2. 移除错误的二次遍历:原代码里每个方向都有两次蛇身遍历,第二次是错误的,必须删掉
  3. 优化代码冗余:把方向控制和移动逻辑提取成函数,避免重复代码
  4. 修复边界判断错误:原代码里所有方向的游戏结束判断都用start->y == 0,明显错误,要对应各自的边界

修正后的完整代码

#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>

int point_x = 0, point_y = 0;
int dir = 0; // 0:上 1:下 2:左 3:右

struct snake
{
    int x, y;
    struct snake *next;
    struct snake *prev;
} *start, *tail;

void create()
{
    struct snake *ptr = (struct snake *)malloc(sizeof(struct snake));
    ptr->next = NULL;
    ptr->prev = NULL;

    if (start == NULL)
    {
        start = ptr;
        tail = ptr;
    }
    else
    {
        tail->next = ptr;
        ptr->prev = tail;
        tail = ptr;
    }
}

void gotoxy(int x, int y)
{
    COORD CRD;
    CRD.X = x;
    CRD.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CRD);
}

void generatePoint()
{
    srand(time(0));
    point_x = rand() % 120;
    point_y = rand() % 30;
}

void drawSnake()
{
    struct snake *temp = start;
    while (temp != NULL)
    {
        gotoxy(temp->x, temp->y);
        printf("%c", (char)254);
        temp = temp->next;
    }
}

void moveSnake()
{
    // 先记录头部的旧位置
    int old_x = start->x;
    int old_y = start->y;

    // 移动头部
    switch(dir)
    {
        case 0: start->y--; break;
        case 1: start->y++; break;
        case 2: start->x--; break;
        case 3: start->x++; break;
    }

    // 从第二个节点开始,依次移动到前一个节点的旧位置
    struct snake *temp = start->next;
    while (temp != NULL)
    {
        int curr_x = temp->x;
        int curr_y = temp->y;
        temp->x = old_x;
        temp->y = old_y;
        old_x = curr_x;
        old_y = curr_y;
        temp = temp->next;
    }
}

int checkCollision()
{
    // 边界碰撞
    if (start->x < 0 || start->x >= 120 || start->y < 0 || start->y >= 30)
        return 1;
    // 自身碰撞(可选)
    struct snake *temp = start->next;
    while (temp != NULL)
    {
        if (start->x == temp->x && start->y == temp->y)
            return 1;
        temp = temp->next;
    }
    return 0;
}

int main()
{
    // 隐藏光标
    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(consoleHandle, &info);

    start = NULL;
    int points = 0;
    char ch;

    // 初始化蛇(3节)
    create();
    start->x = 60;
    start->y = 15;
    create();
    start->next->x = 60;
    start->next->y = 16;
    create();
    tail->x = 60;
    tail->y = 17;

    generatePoint();

    while(1)
    {
        // 处理方向输入
        if (_kbhit())
        {
            ch = _getch();
            switch(ch)
            {
                case 'w': if (dir != 1) dir = 0; break; // 不能直接反向
                case 's': if (dir != 0) dir = 1; break;
                case 'a': if (dir != 3) dir = 2; break;
                case 'd': if (dir != 2) dir = 3; break;
                case 27: exit(0); // ESC退出
            }
        }

        system("cls");
        moveSnake();

        // 检查是否吃到食物
        if (start->x == point_x && start->y == point_y)
        {
            points++;
            create();
            // 新节点放在尾部旧位置
            tail->x = tail->prev->x;
            tail->y = tail->prev->y;
            generatePoint();
        }

        // 绘制食物
        gotoxy(point_x, point_y);
        printf("\033[32m%c\033[0m", (char)254);

        // 绘制蛇
        drawSnake();

        // 绘制分数
        gotoxy(110, 0);
        printf("\033[34mPoints: %d\033[0m", points);

        // 检查碰撞
        if (checkCollision())
        {
            system("cls");
            gotoxy(55, 15);
            printf("\033[31mGame over!\033[0m");
            system("pause>nul");
            exit(0);
        }

        Sleep(90);
    }
    return 0;
}

关键修改说明

  • 移动逻辑:moveSnake函数里先记录头部旧位置,然后从第二个节点开始,每个节点都移动到前一个的旧位置,这样就能保留蛇身的弯曲形态
  • 方向控制:添加了方向变量dir,避免重复的方向分支代码,同时限制不能直接反向移动(比如向上时不能直接按向下)
  • 尾部追踪:新增tail指针,方便快速添加新节点,不用每次遍历找尾部
  • 碰撞检测:完善了边界碰撞和自身碰撞的判断,原代码的边界判断完全错误,现在修正为对应上下左右的边界

内容的提问来源于stack exchange,提问作者Sumit Bose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:26:59