Home > OS >  2D Raylib Texture Collisions
2D Raylib Texture Collisions

Time:03-11

I was wondering how to properly handle collisions in Raylib. After setting up the basics, like a window, I would first load in the player texture, like so:

Texture2D playerTexture = LoadTexture("Player.png");

After that, I would draw the texture, with the Raylib function DrawTextureEx which allows me to adjust the rotation and scale of the texture. Then, I would add a simple movement script for the player, and that would be pretty much it.

As for collisions, I would just be testing the player collision on a rectangle. To get the area for the rectangle, I would just create a simple Rectangle struct like this:

Rectangle rect1 = {100, 100, 50, 50};

As for getting the player area, I would make something similar:

Rectangle playerArea = {player.x, player.y, playerTexture.width*player.scale, playerTexture.height*player.scale} //Values are stored in Player struct

However, when I try to check the collisons like this, nothing happens:

    if (CheckCollisionRecs(playerArea, rect1)) {
        DrawText("Collided", 5, 5, 25, BLACK);
    }

Here's my full code, if needed:

#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>

#define WIDTH 1200 
#define HEIGHT 800

typedef struct {
    const int width;
    const int height;
    int FPS;
} Window;

Window window = {
    .FPS = 60,
};

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

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

} Player;

Player player = {

    .pos = {WIDTH/2, HEIGHT/2},
    .acc = {0, 0},
    .vel = {0, 0},
    .width = 25,
    .height = 25,

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

void movePlayer();
int rectCollide();

int main() {

    InitWindow(WIDTH, HEIGHT, "Window");
    SetTargetFPS(window.FPS);

    Texture2D playerImg = LoadTexture("Player.png");

    Rectangle playerArea = {player.pos.x, player.pos.y, playerImg.width*player.scale, playerImg.height*player.scale};
    Rectangle rect1 = {100, 100, 50, 50};

    Camera2D camera = { 0 };
    camera.target = (Vector2){ player.pos.x   20.0f, player.pos.y   20.0f };
    camera.offset = (Vector2){WIDTH/2.0f, HEIGHT/2.0f };
    camera.rotation = 0.0f;
    camera.zoom = 1.0f;

    if (CheckCollisionRecs(playerArea, rect1)) {
        DrawText("Collided", 5, 5, 25, BLACK);
    }

    while (!WindowShouldClose()) {

        BeginDrawing();
        ClearBackground(SKYBLUE);

        movePlayer();

        camera.target = (Vector2){ player.pos.x   20, player.pos.y   20 };

        BeginMode2D(camera);
        DrawRectangle(100, 100, 50, 50, BLACK);
        DrawTextureEx(playerImg, player.pos, player.rotation, player.scale, RAYWHITE);
        
        EndMode2D();

        EndDrawing();
    }
    UnloadTexture(playerImg);

    CloseWindow();

    return 0;
}

void movePlayer() {
    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 (IsKeyDown(KEY_UP) && player.vel.y > -player.maxVel) {
        player.acc.y = -player.accSpeed;
    } else if (IsKeyDown(KEY_DOWN) && player.vel.x < player.maxVel) {
        player.acc.y = player.accSpeed;
    } else if (abs(player.vel.y) > 0.2) {
        if (player.vel.y < 0) {
            player.acc.y = player.friction;
        } else {
            player.acc.y = -player.friction;
        }
    } else {
        player.vel.y = 0;
        player.acc.y = 0;
    }
    player.vel.y  = player.acc.y;
    player.pos.y  = player.vel.y;
}

int rectCollide(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
  return x1   w1 > x2 && x1 < x2   w2 && y1   h1 > y2 && y1 < y2   h2;
}

And so, I was wondering: first of all, is there a better way to get the area of the texture, without having to create a Rectangle struct for each texture, and multiply the scale by the texture width and height? Secondly, I was wondering why my collisions aren't being detected. What is wrong with my code?

CodePudding user response:

The collision check

if (CheckCollisionRecs(playerArea, rect1))

precedes the event loop.

Even moving it inside the loop will not have any effect, as playerArea is never updated in your event loop.

A quick fix would be to update the collision box after moving the player.

(example snippet of main, without images)

Rectangle playerArea;    
Rectangle rect1 = {100, 100, 50, 50};    
    
while (!WindowShouldClose()) {    
    movePlayer();    
        
    playerArea = (Rectangle) {    
        player.pos.x,                
        player.pos.y,                
        player.width,     
        player.height,     
    };    
        
    camera.target = (Vector2){ player.pos.x   20, player.pos.y   20 };    
            
    BeginDrawing();    
        ClearBackground(SKYBLUE);    
         
        BeginMode2D(camera);    
        
        DrawRectangleRec(rect1, RED);    
        DrawRectangle(player.pos.x, player.pos.y, player.width, player.height, RAYWHITE);    
    
        EndMode2D();    
            
        if (CheckCollisionRecs(playerArea, rect1))
            DrawText("Collided", 5, 5, 25, BLACK);     
    EndDrawing();    
}
  • Related