Raylib X 碰撞响应无法正常工作

发布于 2025-01-13 23:32:06 字数 7392 浏览 5 评论 0原文

我一直在用 C 和 Raylib 制作游戏,并且我已经成功地使 Y 轴上的碰撞起作用,但 X 轴上却不起作用。这就是当玩家落在顶部时发生的情况 游戏中的矩形:

在此处输入图像描述

我已尝试以各种可能的方式调整碰撞,但仍然无法正常工作。我希望玩家能够在方块顶部自由移动,并且当玩家从方块上掉下来时,能够滑下方块但不能穿过它,就像普通的实心平台方块一样。目前,玩家卡在方块的边缘(如图所示)并向下滑动。每当玩家试图降落在方块顶部时,玩家就会被传送到角落(如图所示)。

这是我的碰撞代码:

        for (int i = 0; i < MAX_BUILDINGS; i++) {
            if (CheckCollisionRecs(playerArea, buildings[i])) {
                DrawText("Collided", 10, 10, 25, BLACK);
            
                //Y COLLISIONS
                if (player.vel.y > 0) {
                    player.pos.y = buildings[i].y - player.height;
                    player.vel.y = 0;
                    player.acc.y = 0;
                    player.canJump = true;
                }

                //X COLLISIONS
                if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
                        player.pos.x = buildings[i].x + buildings[i].width;
                    } else { // If the player moved right and collided with the left side of block
                        player.pos.x = buildings[i].x - player.width;
                    }
                    player.vel.x = 0;
            }
        }

我只是循环遍历一个称为建筑物的矩形数组,然后使用 buildings[i] 检查所有矩形的碰撞。

如果需要的话,这是我的完整代码:

#include "raylib.h"

#include <math.h>
#include <stdio.h>
#include <stdbool.h>

#define MAX_BUILDINGS 100



int main(void) {

    const int screenWidth = 1600;
    const int screenHeight = 1000;

    InitWindow(screenWidth, screenHeight, "Window Title");

    /*---STRUCTS---*/
    typedef struct {
        int FPS;
        int frames;
    } Window;

    Window window = {
        .FPS = 60,
        .frames = 0,
    };

    Rectangle buildings[MAX_BUILDINGS] = { 0 };
    Color buildColors[MAX_BUILDINGS] = { 0 };
    int buildRotation[MAX_BUILDINGS] = { 0 };

    /*---BUILDINGS---*/
    int spacing = screenWidth/2;

    for (int i = 0; i < MAX_BUILDINGS; i++) {
        buildings[i].width = (float)GetRandomValue(750, 1000);
        buildings[i].height = screenHeight*2;
        buildings[i].y = (float)GetRandomValue(200, 500);
        buildings[i].x = spacing;

        spacing += (int)buildings[i].width + GetRandomValue(250, 500);

        buildColors[i] = BLUE;
        buildRotation[i] = 0;

    }

    typedef struct {
        float width;
        float height;
        Vector2 pos;
        Vector2 vel;
        Vector2 acc;

        double accSpeed;
        int maxVel;
        double friction;
        double rotation;
        double scale;

        float jumpForce;
        float gravity;
        bool canJump;
    } Player;

    Player player = {
        .width = 50,
        .height = 100,
        .pos = {buildings[0].x + buildings[0].width/2 - player.width/2, buildings[0].y - player.height},
        .vel = {0, 0},
        .acc = {0, 0},

        .accSpeed = 0.15,
        .maxVel = 7,
        .friction = 0.2,
        .rotation = 0,
        .scale = 0.5,

        .jumpForce = 20,
        .gravity = 0.5,
        .canJump = true,
    };

   typedef struct {
        float x;
        float y;
        int speed;
    } Camera;

    Camera cameraPos = {
        .x = screenWidth/2,
        .y = screenHeight/2,
        .speed = 5,
    };

    Camera2D camera = { 0 };
    camera.target = (Vector2) {cameraPos.x, cameraPos.y};
    camera.offset = (Vector2) {screenWidth/2, screenHeight/2};
    camera.rotation = 0.0f;
    camera.zoom = 1.0f;


    SetTargetFPS(window.FPS);

    Rectangle playerArea;

    /*---MAIN GAME LOOP---*/
    while (!WindowShouldClose()) {
        window.frames++;
        // Update
        if (window.frames >= 3*window.FPS) {
            camera.target.x += cameraPos.speed;
            camera.target.y = player.pos.y;
        }
        playerArea = (Rectangle) {    
            player.pos.x,                
            player.pos.y,                
            player.width,  
            player.height,
        };   
        //----------------------------------------------------------------------------------
        // TODO: Update your variables here

        for (int i = 0; i < MAX_BUILDINGS; i++) {
            if (CheckCollisionRecs(playerArea, buildings[i])) {
                DrawText("Collided", 10, 10, 25, BLACK);
            
                //Y COLLISIONS
                if (player.vel.y > 0) {
                    player.pos.y = buildings[i].y - player.height;
                    player.vel.y = 0;
                    player.acc.y = 0;
                    player.canJump = true;
                }

                //X COLLISIONS
                if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
                        player.pos.x = buildings[i].x + buildings[i].width;
                    } else { // If the player moved right and collided with the left side of block
                        player.pos.x = buildings[i].x - player.width;
                    }
                    player.vel.x = 0;
            }
        }

        if (IsKeyDown(KEY_LEFT) && player.vel.x > -player.maxVel) {
            player.acc.x = -player.accSpeed;
        } else if (IsKeyDown(KEY_RIGHT) && player.vel.x < player.maxVel) {
            player.acc.x = player.accSpeed;
        } else if (abs(player.vel.x) > 0.2) {
            if (player.vel.x < 0) {
                player.acc.x = player.friction;
            } else {
                player.acc.x = -player.friction;
            }
        } else {
            player.vel.x = 0;
            player.acc.x = 0;
        }
        player.vel.x += player.acc.x;
        player.pos.x += player.vel.x;

            if (IsKeyPressed(KEY_UP) && player.vel.y == 0 && player.acc.y == 0 && player.canJump) {
                player.canJump = false;
                player.vel.y = -player.jumpForce;
            }
        player.acc.y += player.gravity;
        player.vel.y += player.acc.y;
        player.pos.y += player.vel.y;
        player.acc.y = 0;
        //----------------------------------------------------------------------------------

        // Draw
        //----------------------------------------------------------------------------------
        BeginDrawing();
            ClearBackground(RAYWHITE); 

            BeginMode2D(camera);  
            for (int i = 0; i < MAX_BUILDINGS; i++) {
                DrawRectanglePro(buildings[i], (Vector2) {0, 0}, buildRotation[i], buildColors[i]);
            }
            DrawRectangle(player.pos.x, player.pos.y, player.width, player.height, RED); 
            EndMode2D();

        EndDrawing();
        //----------------------------------------------------------------------------------
    }

    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

因此,有人可以告诉我为什么 X 轴的碰撞被破坏吗?是因为我的代码检测到碰撞的顺序吗?我的碰撞逻辑坏了吗?

感谢您的任何帮助。

I've been making a game with C and Raylib, and I've managed to get the collisions on the Y axis working, but not on the X axis. This is what happens when the player lands on the top of
a rectangle in the game:

enter image description here

I've tried adjusting the collisions in every way possible, but I still have not gotten it to work. I want the player to be able to move freely on top of the block, and when the player falls off the block, be able to slide down the block but not go through it, just like a normal solid platform block. Currently, the player gets stuck on the edge of the block (as seen from the image), and slides down. Anytime the player tries to land on top of the block, the player gets teleported to the corner (as seen on the image).

Here is my collision code:

        for (int i = 0; i < MAX_BUILDINGS; i++) {
            if (CheckCollisionRecs(playerArea, buildings[i])) {
                DrawText("Collided", 10, 10, 25, BLACK);
            
                //Y COLLISIONS
                if (player.vel.y > 0) {
                    player.pos.y = buildings[i].y - player.height;
                    player.vel.y = 0;
                    player.acc.y = 0;
                    player.canJump = true;
                }

                //X COLLISIONS
                if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
                        player.pos.x = buildings[i].x + buildings[i].width;
                    } else { // If the player moved right and collided with the left side of block
                        player.pos.x = buildings[i].x - player.width;
                    }
                    player.vel.x = 0;
            }
        }

I'm just looping through an array of rectangles, called buildings, and then checking collisions for all of them with buildings[i].

Here is my full code if needed:

#include "raylib.h"

#include <math.h>
#include <stdio.h>
#include <stdbool.h>

#define MAX_BUILDINGS 100



int main(void) {

    const int screenWidth = 1600;
    const int screenHeight = 1000;

    InitWindow(screenWidth, screenHeight, "Window Title");

    /*---STRUCTS---*/
    typedef struct {
        int FPS;
        int frames;
    } Window;

    Window window = {
        .FPS = 60,
        .frames = 0,
    };

    Rectangle buildings[MAX_BUILDINGS] = { 0 };
    Color buildColors[MAX_BUILDINGS] = { 0 };
    int buildRotation[MAX_BUILDINGS] = { 0 };

    /*---BUILDINGS---*/
    int spacing = screenWidth/2;

    for (int i = 0; i < MAX_BUILDINGS; i++) {
        buildings[i].width = (float)GetRandomValue(750, 1000);
        buildings[i].height = screenHeight*2;
        buildings[i].y = (float)GetRandomValue(200, 500);
        buildings[i].x = spacing;

        spacing += (int)buildings[i].width + GetRandomValue(250, 500);

        buildColors[i] = BLUE;
        buildRotation[i] = 0;

    }

    typedef struct {
        float width;
        float height;
        Vector2 pos;
        Vector2 vel;
        Vector2 acc;

        double accSpeed;
        int maxVel;
        double friction;
        double rotation;
        double scale;

        float jumpForce;
        float gravity;
        bool canJump;
    } Player;

    Player player = {
        .width = 50,
        .height = 100,
        .pos = {buildings[0].x + buildings[0].width/2 - player.width/2, buildings[0].y - player.height},
        .vel = {0, 0},
        .acc = {0, 0},

        .accSpeed = 0.15,
        .maxVel = 7,
        .friction = 0.2,
        .rotation = 0,
        .scale = 0.5,

        .jumpForce = 20,
        .gravity = 0.5,
        .canJump = true,
    };

   typedef struct {
        float x;
        float y;
        int speed;
    } Camera;

    Camera cameraPos = {
        .x = screenWidth/2,
        .y = screenHeight/2,
        .speed = 5,
    };

    Camera2D camera = { 0 };
    camera.target = (Vector2) {cameraPos.x, cameraPos.y};
    camera.offset = (Vector2) {screenWidth/2, screenHeight/2};
    camera.rotation = 0.0f;
    camera.zoom = 1.0f;


    SetTargetFPS(window.FPS);

    Rectangle playerArea;

    /*---MAIN GAME LOOP---*/
    while (!WindowShouldClose()) {
        window.frames++;
        // Update
        if (window.frames >= 3*window.FPS) {
            camera.target.x += cameraPos.speed;
            camera.target.y = player.pos.y;
        }
        playerArea = (Rectangle) {    
            player.pos.x,                
            player.pos.y,                
            player.width,  
            player.height,
        };   
        //----------------------------------------------------------------------------------
        // TODO: Update your variables here

        for (int i = 0; i < MAX_BUILDINGS; i++) {
            if (CheckCollisionRecs(playerArea, buildings[i])) {
                DrawText("Collided", 10, 10, 25, BLACK);
            
                //Y COLLISIONS
                if (player.vel.y > 0) {
                    player.pos.y = buildings[i].y - player.height;
                    player.vel.y = 0;
                    player.acc.y = 0;
                    player.canJump = true;
                }

                //X COLLISIONS
                if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
                        player.pos.x = buildings[i].x + buildings[i].width;
                    } else { // If the player moved right and collided with the left side of block
                        player.pos.x = buildings[i].x - player.width;
                    }
                    player.vel.x = 0;
            }
        }

        if (IsKeyDown(KEY_LEFT) && player.vel.x > -player.maxVel) {
            player.acc.x = -player.accSpeed;
        } else if (IsKeyDown(KEY_RIGHT) && player.vel.x < player.maxVel) {
            player.acc.x = player.accSpeed;
        } else if (abs(player.vel.x) > 0.2) {
            if (player.vel.x < 0) {
                player.acc.x = player.friction;
            } else {
                player.acc.x = -player.friction;
            }
        } else {
            player.vel.x = 0;
            player.acc.x = 0;
        }
        player.vel.x += player.acc.x;
        player.pos.x += player.vel.x;

            if (IsKeyPressed(KEY_UP) && player.vel.y == 0 && player.acc.y == 0 && player.canJump) {
                player.canJump = false;
                player.vel.y = -player.jumpForce;
            }
        player.acc.y += player.gravity;
        player.vel.y += player.acc.y;
        player.pos.y += player.vel.y;
        player.acc.y = 0;
        //----------------------------------------------------------------------------------

        // Draw
        //----------------------------------------------------------------------------------
        BeginDrawing();
            ClearBackground(RAYWHITE); 

            BeginMode2D(camera);  
            for (int i = 0; i < MAX_BUILDINGS; i++) {
                DrawRectanglePro(buildings[i], (Vector2) {0, 0}, buildRotation[i], buildColors[i]);
            }
            DrawRectangle(player.pos.x, player.pos.y, player.width, player.height, RED); 
            EndMode2D();

        EndDrawing();
        //----------------------------------------------------------------------------------
    }

    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

Therefore, could someone please tell me why the collisions are broken for the X axis? Is it because of the order of my code in which the collisions are detected? Is my collision logic broken?

Thanks for any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

丢了幸福的猪 2025-01-20 23:32:06

好的,现在是一些基础知识时间了。这里你需要一些数学知识,但在本例中你试图在两个矩形之间进行碰撞。它们的公式是
<代码>rec1.x < (rec2.x + rec2.width) 和相反的 rec2.x < (rec1.x + rec1.width)。要获得 Y 碰撞,您只需执行以下操作 rec1.y < (rec2.y + rec2.height)rec2.y < (rec1.y + rec1.height)。在这个解释之后,您应该得到以下内容:

if(rec1.x < (rec2.x + rec2.width) && rec2.x < (rec1.x + rec1.width) &&
rec1.y < (rec2.y + rec2.height) && rec2.y < (rec1.y + rec1.height)) collision = true;

当我们知道两个轴都有主动碰撞后,一切都变得简单了。

注意:根据我的个人经验,我创建了一个包含所有必要变量的结构。


typedef struct GameObject {
    Vector2 position;       // Vector2 contains both X and Y positions
    Vector2 speed;          // Used for speed, can be used in both X and Y axis
    float scale;            // GameObject scale
    Texture2D texture;      // GameOobject texture
    bool canCollide;        //Check if you can collide with a GameObject
    bool hasCollided;       //Check if the GameObject has already collided with something
           
} GameObject;

另外,请记住,我使用纹理而不是矩形,但我将游戏对象表示为矩形,因此它基本上是相同的。

希望这对您有所帮助并祝您一切顺利!

Ok, some basics time. Here you need some maths, but in this case you're trying to make a collision between two rectangles. The formula for them is
rec1.x < (rec2.x + rec2.width) and the opposite rec2.x < (rec1.x + rec1.width). And to get the Y collisions you just do it rec1.y < (rec2.y + rec2.height) and rec2.y < (rec1.y + rec1.height). After this explanation you should have something along the lines of:

if(rec1.x < (rec2.x + rec2.width) && rec2.x < (rec1.x + rec1.width) &&
rec1.y < (rec2.y + rec2.height) && rec2.y < (rec1.y + rec1.height)) collision = true;

And after we know we have active collisions for both axis, everything is straight forward.

Note: From my personal experience I made a struct with all the necessary variables.


typedef struct GameObject {
    Vector2 position;       // Vector2 contains both X and Y positions
    Vector2 speed;          // Used for speed, can be used in both X and Y axis
    float scale;            // GameObject scale
    Texture2D texture;      // GameOobject texture
    bool canCollide;        //Check if you can collide with a GameObject
    bool hasCollided;       //Check if the GameObject has already collided with something
           
} GameObject;

Also, keep in mind that I used textures instead of rectangles, but I represented my GameObjects as rectangles so it's basically the same.

Hope this helped you and wish you all the best!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文