The 2024 Wheel Reinvention Jam is in 16 days. September 23-29, 2024. More info

Problems with tilemap collisions C++/Raylib

Yes hello all. I'm having a problems with my collisions in my demo I'm making. Sometimes the player collides with objects and sometimes they pass right through. I don't know if it's because I'm using different sizes for the tile map and players, or what's going on. any help is appreciated. Thanks.

My first game 2024-06-30 12-42-23.mp4

https://pastebin.com/nZrQi6tb


Edited by crs2she on

When asking some issue like this, it would help to have a zip with either everything we need to compile as simply as possible (batch file or the command line to use, no build system), or the binary + source + debug symbols (pdb) to be able to step through the code.

This part of the code looks different from the rest:

if (RIGHT) {
    nebData.pos.x += playervec * dt;
    nebData.rec.y = 64;
    Rectangle rec1{ (int)nebData.pos.x+24, (int)nebData.pos.y+9 };
			
    for (int i = 0;i < sWidth;i++) {
        for (int j = 0;j < sHeigth;j++) {
            if (CheckCollisionRecs(rec1, rec[i][j])) {
                if (type[i][j] == 1) {
                    nebData.pos.x -= playervec * dt;
                }
            }
         }
     }	

     RIGHT = false;
     camera.target = { nebData.pos.x + 20.0f, nebData.pos.y + 20.0f };
}

This might be a typo as other directions use 9 instead of 24: nebData.pos.x+24. Also I'm not sure I understand why you add an offset when creating the rectangle. Doesn't it make the collision at the wrong location ?

If you can, try to draw the collision rectangle for the player and the tiles to see if they are what and where you expect.

A few other notes:

  • doing x or y + the movement before the loop and then undoing it when there is a collision might not put you back at the exact same position because of floating point precision. I would do this instead:
f32 new_x = current_x + velocity * dt;
Rectangle r = { ... }
b32 collision = false;
for ( x... ) {
    for ( y... ) {
        if ( RectIntersects( r, ... ) ) {
            collision = true;
            break;
        }
    }
}
if ( !collision ) {
    current_x = new_x;
}
  • When you check for collision you don't stop the loop when there is a collision, so you might undo the position change several time, if there are other collision detected (e.g. the character try to move between two tiles).

  • When you create the rect for testing collision, you don't specify a width and height. I don't know what RayLib initialize the rectangle to in that case, but you might need to verify that it's doing what you want.

  • You also have several variable called rec1 in nested scopes. This is called variable shadowing and can make things confusing sometimes if you don't realize that you're modifying or reading the wrong thing.

  • Shouldn't playervec be playervel (for velocity) ?

  • When using two dimensional arrays, I often use the height as the first index and the width as the second index. u8 tiles[ height ][ width ] = { ... }. It generally makes it easier to initialize the array, as you specify elements row by row, instead of column by column.


Edited by Simon Anciaux on

Ok thanks I will try out changes. Also 24 was just a number I was trying out to see if it made any difference, but thanks again for the insight.

I just thought that the pseudo code I wrote wouldn't do what I expected because there are two loops, so break would only break of the inner loop. So we would need to use the collision boolean in both loop conditions to exit both loops.

f32 new_x = current_x + velocity * dt;
Rectangle r = { ... }
b32 collision = false;
for ( ...; !collision && x < sWidth;... ) {
    for ( ...; !collision && y < sHeight;... ) {
        if ( RectIntersects( r, ... ) ) {
            collision = true;
        }
    }
}
if ( !collision ) {
    current_x = new_x;
}

Edited by Simon Anciaux on

Thanks it worked great. Sorry for late reply.


Replying to mrmixer (#30220)