문제

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;
}
도움이 되었습니까?

해결책

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).

다른 팁

It sounds like you're only catching your collisions after the fact. Most likely you're moving the player into the rectangle, so subsequent collision checks always return true. There are a few ways to fix this, but I think the easiest is to catch the collision before it happens, not after, and prevent it.

Let's say the player is falling and you update the player's position each frame. Before you move the player's position is changed, you want to check if the new position is going to intersect a rectangle. If the new position will intersect a rectangle, you want to change how far the player is moved (let's call this distance the step) so that it touches the edge of the rectangle, but doesn't intersect it.

Add checking colision in move function. Pass new position (as if it was moved) to checking colision function. If there will occur collision return false in move func, if there isn't move and return true.

I see you used Lazyfoo code. So did I. I had the same problem as you but i solved it. Here's how i did it.

hero.move(true);   // hero is moved in some direction 
if (check_collision(hero.rect(),box.rect()))  // check for collision after movement 
{
    hero.move(false); // if collision happend , move hero back 
}

SDL_flip(screen);

It will look like hero has stopped on block but in reality it will move forward then, if collision happens, move back. After this he will be displayed. The true and false arguments are used to tell the function if the hero must be moved forward (x += speed) or backward (x -= speed). If you will need some code from my collision code just ask.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top