尝试用 C 和 raylib 制作贪吃蛇游戏。添加吃苹果后的未定义行为
Trying to make a snake game in C and raylib. Undefined behaviour after adding eating apples
所以,我尝试用 C 语言用 raylib 制作一个简单的贪吃蛇游戏,在添加了吃苹果的功能后,基本上一切都坏了。
我这样做的方式是,有一个 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;
}
在添加食物之前游戏是否成功?例如,当蛇的长度为 3 时,它是如何移动的?,因为在你的代码中考虑蛇如何改变方向时,似乎如果蛇在某个方向移动并改变方向,那么所有部分都会改变方向:
for (int i = 0; i <= score; i++)
{
playerLoc[i].x += playerDir.x;
playerLoc[i].y += playerDir.y;
}
假设蛇的长度为 5 并且垂直移动(在 y-axis 上)玩家按下 'D' 然后方向将向右(x-axis),所以基本上只有头部必须向右移动,其余的必须继续移动 y-axis,然后头部旁边的方块将向右移动,其余的 body 将继续移动 y-axis。但是在你的代码中所有方块同时改变它们的方向,如果你开始你的游戏时只有一个方块你不会注意到这一点但是在进食和增加尺寸之后你会注意到错误。
你必须考虑的第二件事是何时改变方向,例如如果用户向右移动(在按下 'D' 之后)然后如果他按下 'A' 那么蛇必须不会改变方向,只有在垂直方向时才会改变,y-axis 也是如此,但是您的代码没有考虑这些特殊情况。
最后,当你在吃蛇后给蛇添加一个正方形时,蛇不再长了:
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.
另外还要考虑食物在边界的可能性,在这种情况下使用方向加方块可能会导致蛇超出限制,在这种情况下你需要加一个方块仅在用户按下有效方向后,您可以添加代码以考虑在食物位于边界(或靠近蛇的body)时仅在用户按下方向时添加正方形,或者您可以找到其他解决方案,例如在尾部添加正方形,或者让蛇的头部移动一格,而其余的 body 被冻结一个循环,然后在头部 body 与蛇的位置之间添加一个正方形头部的先前位置等...
在头部添加一个正方形可能会给用户带来糟糕的体验,因为头部会改变它的位置而不受他的干扰。
所以,我尝试用 C 语言用 raylib 制作一个简单的贪吃蛇游戏,在添加了吃苹果的功能后,基本上一切都坏了。 我这样做的方式是,有一个 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;
}
在添加食物之前游戏是否成功?例如,当蛇的长度为 3 时,它是如何移动的?,因为在你的代码中考虑蛇如何改变方向时,似乎如果蛇在某个方向移动并改变方向,那么所有部分都会改变方向:
for (int i = 0; i <= score; i++)
{
playerLoc[i].x += playerDir.x;
playerLoc[i].y += playerDir.y;
}
假设蛇的长度为 5 并且垂直移动(在 y-axis 上)玩家按下 'D' 然后方向将向右(x-axis),所以基本上只有头部必须向右移动,其余的必须继续移动 y-axis,然后头部旁边的方块将向右移动,其余的 body 将继续移动 y-axis。但是在你的代码中所有方块同时改变它们的方向,如果你开始你的游戏时只有一个方块你不会注意到这一点但是在进食和增加尺寸之后你会注意到错误。
你必须考虑的第二件事是何时改变方向,例如如果用户向右移动(在按下 'D' 之后)然后如果他按下 'A' 那么蛇必须不会改变方向,只有在垂直方向时才会改变,y-axis 也是如此,但是您的代码没有考虑这些特殊情况。
最后,当你在吃蛇后给蛇添加一个正方形时,蛇不再长了:
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.
另外还要考虑食物在边界的可能性,在这种情况下使用方向加方块可能会导致蛇超出限制,在这种情况下你需要加一个方块仅在用户按下有效方向后,您可以添加代码以考虑在食物位于边界(或靠近蛇的body)时仅在用户按下方向时添加正方形,或者您可以找到其他解决方案,例如在尾部添加正方形,或者让蛇的头部移动一格,而其余的 body 被冻结一个循环,然后在头部 body 与蛇的位置之间添加一个正方形头部的先前位置等... 在头部添加一个正方形可能会给用户带来糟糕的体验,因为头部会改变它的位置而不受他的干扰。