试图用 C 和 raylib 制作蛇游戏。添加吃苹果后未定义的行为

Posted

技术标签:

【中文标题】试图用 C 和 raylib 制作蛇游戏。添加吃苹果后未定义的行为【英文标题】:Trying to make a snake game in C and raylib. Undefined behaviour after adding eating apples 【发布时间】:2021-12-27 17:48:46 【问题描述】:

所以,我正在尝试用 raylib 用 C 语言制作一个简单的蛇游戏,在添加了吃苹果的能力之后,基本上一切都崩溃了。 我这样做的方式是,有一个 Vector2 数组,它给出了蛇的每个正方形的位置,它被渲染为 20x20 网格。 这是代码,这有点像意大利面条,因为我是一个糟糕的程序员,但我希望有人能帮助我。

#include <stdlib.h>
#include <time.h>
#include <raylib.h>

#define WIDTH 1080
#define HEIGHT 1080
#define FPS 4
#define GRIDSIZE 20

int main()

    // Random Numbers
    srand(time(NULL));

    // Define locations
    Vector2 playerLoc[10] = (Vector2) rand() % GRIDSIZE, rand() % GRIDSIZE;
    Vector2 appleLoc = (Vector2) rand() % GRIDSIZE, rand() % GRIDSIZE;

    // Player Score
    int score = 0;
    // Define Direction
    Vector2 playerDir = (Vector2) 1, 0;

    // With of Grid Squares
    int gridSize = HEIGHT / GRIDSIZE;

    // Initialization
    InitWindow(WIDTH, HEIGHT, "Snake Game Test");

    SetTargetFPS(FPS);

    while (!WindowShouldClose())
    
        // Update Variables Here
        if (IsKeyPressed('D') || IsKeyPressed('A'))
        
            playerDir.x = (int) IsKeyPressed('D') - (int) IsKeyPressed('A');
            playerDir.y = 0.0f;
        
        else if (IsKeyPressed('S') || IsKeyPressed('W'))
        
            playerDir.y = (int) IsKeyPressed('S') - (int) IsKeyPressed('W');
            playerDir.x = 0;
        
        for (int i = 0; i <= score; i++)
        
            playerLoc[i].x += playerDir.x;
            playerLoc[i].y += playerDir.y;
        
        if (playerLoc[0].x < 0)
            break;
        else if (playerLoc[0].x >= 1080)
            break;
        else if (playerLoc[0].y < 0)
            break;
        else if (playerLoc[0].y >= 1080)
            break;

        if (playerLoc[0].x == appleLoc.x && playerLoc[0].y == appleLoc.y)
        
            appleLoc = (Vector2) rand() % GRIDSIZE, rand() % GRIDSIZE;
            score++;
            playerLoc[score].x = playerLoc[score - 1].x + (playerDir.x * -1);
            playerLoc[score].y = playerLoc[score - 1].y + (playerDir.y * -1);
        

        // Draw
        BeginDrawing();

            ClearBackground(RAYWHITE);

            for (int i = 0; i < GRIDSIZE; i++)
            
                for (int j = 0; j < GRIDSIZE; j++)
                
                    for (int k = 0; k <= score; k++)
                    
                        if (i == playerLoc[k].x && j == playerLoc[k].y)
                            DrawRectangle(i * gridSize, j * gridSize, gridSize, gridSize, BLACK);
                    
                    if (i == appleLoc.x && j == appleLoc.y)
                    
                        DrawRectangle(i * gridSize, j * gridSize, gridSize, gridSize, RED);
                    
                
            

        EndDrawing();
        // Update Late Variables Here
    

    // De-Initialization
    CloseWindow();

    return 0;

【问题讨论】:

要有效地调试编译时不会出现警告的 C 程序,您需要使用像 gdb 这样的调试器。盯着你的代码并希望发现问题,或者添加一堆打印语句来“跟踪”,是一个糟糕的解决方案。猜猜我是怎么知道的:P。 【参考方案1】:

在添加食物之前游戏运行正常吗?例如,当蛇从长度 3 开始时,它是如何移动的?,因为在考虑蛇如何在代码中改变方向时,如果蛇在某个方向移动并改变方向,那么所有部分都会改变方向:

    for (int i = 0; i <= score; i++)
        
            playerLoc[i].x += playerDir.x;
            playerLoc[i].y += playerDir.y;
        

假设蛇的长度为 5 并且垂直移动(在 y 轴上)玩家按下“D”然后方向将向右(x 轴),所以基本上只有头部必须向右移动其余的必须继续在y轴上移动,然后头部旁边的方块将向右移动,身体的其余部分将继续在y轴上移动。但是在你的代码中,所有的方块都会同时改变它们的方向,如果你只用一个方块开始你的游戏你不会注意到这一点,但是在吃完并增加大小之后你会注意到错误。

您必须考虑的第二件事是何时改变方向,例如,如果用户向右移动(按“D”后),那么如果他按“A”,那么蛇一定不能改变方向,它会改变仅当它垂直移动时,y 轴也是如此,但您的代码不会考虑这些特殊情况。

最后,当你在吃完蛇后给蛇加一个正方形时,蛇就不再长了:

   playerLoc[score].x = playerLoc[score - 1].x + (playerDir.x * -1);
   playerLoc[score].y = playerLoc[score - 1].y + (playerDir.y * -1);

假设蛇向右移动(用户按“D”),因此根据您的代码 playerDir.x = 1,现在理论上蛇必须向右添加正方形,因此代码必须是 playerLoc[score - 1].x + 1,但是因为你乘以 -1,所以添加的正方形的 x 将等于前一个头的 x 减 1。不需要乘以 -1。

另外你应该考虑食物在边界的可能性,在这种情况下通过使用方向添加一个正方形可能会导致蛇超出限制,在这种情况下你只需要在之后添加一个正方形用户按下一个有效的方向,您可以添加代码以考虑仅当用户按下一个方向时食物在边界(或靠近蛇的身体)时添加正方形,或者您可以找到其他解决方案,例如在尾部添加正方形,或者让蛇的头部移动一个方格,而身体的其余部分被冻结一个周期,然后在头部和身体之间添加一个方格,与之前头部位置的位置,等等...... 在头部添加正方形可能会给用户带来不好的体验,因为头部会在不受他干扰的情况下改变它的位置。

【讨论】:

这个找到了。我在提交答案之前发现了这个,但问题是将整个蛇作为一个块移动,后来我将playerDir更改为向量数组并更改代码以一种“鞭子运动”改变方向跨度>

以上是关于试图用 C 和 raylib 制作蛇游戏。添加吃苹果后未定义的行为的主要内容,如果未能解决你的问题,请参考以下文章

这个贪吃蛇c语言代码在哪里添加啥可以改变它的背景色????

Python制作当年第一款真正意义上的手机游戏——贪吃蛇游戏

Python制作当年第一款手机游戏-贪吃蛇游戏(练习)

用C语言编写贪吃蛇小游戏

如何制作一个简单的小游戏?

指针给出整个数组而不是 C++ RayLib 中的一个字符