Search code examples
c++sdlcollisiongame-developmentrect

Collisions in SDL & C++


How do I calculate a collision between two rects in C++ & SDL, and how do I make the player not able to go through this rect (i.e. ensure one rect cannot pass through the other)?

I know to stop the player would be playeryvel = 0, making the player's Y velocity 0, so they cannot pass through it. My problem is, this will stop ALL vertical movement, when I want to stop movement through the other rect.

My current code uses a function named check_collision(SDL_Rect, SDL_Rect). Here's my the code for the usage, and the actual function.

// This loops through a vector, containing rects.
for (int i=0; i<MAP::wall.size(); i++)
{
    std::cout << i << std::endl;
    cMap.FillCustomRect(MAP::wall.at(i), 0xFFFFFF);
    if (check_collision(cMap.wall.at(i), cDisplay.getPlayer(playerx, playery)))
    {
        exit(0); // It exits just as an example to show if there actually is a collision
    }
}


bool check_collision( SDL_Rect A, SDL_Rect B )
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;

    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;

    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;

     //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }

    if( topA >= bottomB )
    {
        return false;
    }

    if( rightA <= leftB )
    {
        return false;
    }

    if( leftA >= rightB )
    {
        return false;
    }

    //If none of the sides from A are outside B
    return true;
}

Solution

  • Simply push player away from the point of collision, every frame. You don't need boolean tests (collide or not), you need to adjust player position if collision occurs.

    1. Update player position (position += velocity * time);
    2. If collision occurs, push player away from point of collision so no collision occur.

    This can work really well, because you'll be able to "slide" along walls, etc. To do that you need to find point of contact, depth of intersection and direction of intersection (i.e. in which direction you should push the player to move away).

    Of course, you'll need to calculate how far you should move the player, but in 2D it is extremely easy to do.

    You need to calculate how much two rectangles overlap. Then you push player rectangle in the direction (x or y) that overlaps the most (only in x or y direction, unless they're equal).