Sign in to follow this  
Asros

SDL collision problem

Recommended Posts

I have a small problem with SDL collision. I get the collision detection to work when I use velocity as a way to move the character. Now that I move the character using certain number of pixels, the same kind of trick doesn work, because I need to have 4 different collision detection with separated outputs. For example, if the character hits wall above him, I need to "push" the character down (add to the y coordinate) Here is my current collision detection

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;
}

It only has one output: true or false. I figured that I need 5 different outputs (1 per side for collision and 1 when collision doesn't happen). I tried to change bool to int so I would get more outputs, but then I realized that it doesn't work that way. The program checks if the sides from Rec A are outside of Rec B. I would need to get it just the opposite. If one side from A is inside of B, collision happens. I tried to change it for an hour or so but whatever I did, the character started running towards the top of the screen (y=0) I wish someone could tell me, how to get it right. Like if the character hits the wall above him, the funktion returns 1, if the wall below him, returns 2... etc.. etc.

Share this post


Link to post
Share on other sites
This really doesn't have anything to do with SDL (the fact that you're using SDL_Rect to represent your bounding boxes is incidental). This sort of question would probably be more at home in, say, Math & Physics.

Anyway, there are a few ways to do what you're asking.

One way is to use a continuous (swept) test, which is probably the most 'foolproof' method, and can tell you (among other things) exactly where the two boxes collided.

If the relative displacement of the moving boxes is small enough relative to their size, you could compute a 'minimum translation vector' for the pair of boxes, which, assuming that the relative displacement is small, will give you a pretty good idea of which sides of the boxes collided.

You might also be able to make a good guess at which side the player collided from by examining the player velocity vector and/or comparing the positions of the two boxes. I've never tried this approach myself though.

Share this post


Link to post
Share on other sites
An easier way to solve the problem is to simply store the last position of an object before it moves. After it moves, if check_collision returns true, you simply restore the last position as the current position and stop the movement (flags or velocity, depends on your setup) of that object.

By doing this, there is no need to figure out which direction to "push" the object because the last stored position was non-colliding for that object. As long as you evaluate collisions on any move for all objects, you will be able to maintain a valid state of no penetrating objects. A simple example of this would be as follows:

Point A (0, 0)
Point B (1, 0)
Point C (2, 0)

Point A moves to (1, 0)
Collision check runs. A is colliding with B, so A is restored to (0, 0)
Point C moves to (0, 0)
Collision check runs. C is colliding with A, so C is restored to (2, 0)

However, if you decide to move all objects first and then check collisions in an update cycle, you need to be sure that you loop through collision checking until there are no collisions left, restoring all objects that have a collision. A simple example of this would be as follows:

Point A (0, 0)
Point B (1, 0)
Point C (2, 0)

Point A moves to (1, 0)
Point C moves to (0, 0)
Collision check runs. Point A and B are colliding, so you restore the previous locations. A goes to (0, 0) and B stays at (0, 1).

Oops! Point A is now colliding with Point C after one collision check cycle. You need to loop through the objects again, which restores Point C to (2, 0). Afterwards, there are no collisions, so you are done processing.

I'd suggest going with the first approach for the sake of simplicity at the time being.

Since you are working in 2D and are doing simple bounds based collision checking, such a method at this should work fine even with a moderate amount of objects, since all you are doing is simple addition and comparison.

You should be able to use your existing code and integrate a method like this without much work; just store the last position before a move, run your collision checks for that object, and if there are any collisions, restore the saved position.

It's been a while since I've done anything like this, but the theory seems sound to me. [lol]

Share this post


Link to post
Share on other sites
Quote:
Original post by Drew_Benton
An easier way to solve the problem is to simply store the last position of an object before it moves. After it moves, if check_collision returns true, you simply restore the last position as the current position and stop the movement (flags or velocity, depends on your setup) of that object
I have to question this advice a little bit.

As I recall from the OP's other thread, he or she is trying to get this project done quickly, and as such, maybe the above method (which is certainly straightforward and easy to implement) might be a suitable solution. However, I don't think many 'real' games use this method any more, and I certainly wouldn't recommend it for production code (unless it's a puzzle or tile-based game where movement is always in fixed, discrete steps).

One of the problems with this method is that every time an object runs into an obstacle, it will stop at a different distance from the obstacle. If the object is moving slowly enough this may not be noticeable, but for faster moving objects it will most likely be obvious that the object is not stopping 'flush' with the obstacle, but rather is stopping short of it a ways (how short being a basically random function for the object's position and velocity).

Also, in most cases you're not going to want an object to just 'stop' when they run into something, but rather respond in a more or less realistic fashion. For example, in many games, when the character runs into a wall or surface, they will slide along it rather than just stopping cold, and for this you'll need (at least) the collision normal. Information about where and how two objects collided (rather than just if they collided) can be useful for other purposes as well, such as bouncing, handling of 'one-sided' platforms in platform games, and so on.

Finally, although computing the minimum translational vector for two intersecting axis-aligned boxes is a little more involved than the simple collision resolution method you describe above, it's not really that hard - it's actually pretty trivial to implement. Personally, I'd recommend that the OP go with the 'minimum translation vector' method (unless he or she is *really* just trying to get this done, and isn't too concerned about the quality of the simulation).

Share this post


Link to post
Share on other sites
Thanks for the advices. I actually found a simple way to solve this. It was so simple I didn't think of at first. It just hit me when I woke up.

I was stuck with the idea of knowing on which side the collision happened. I was trying to get more outputs than true or false from the collision check when I should have looked the other way. I added a variables xdirection and ydirection to the moving funktion. It was so simple. The collision can't happen on left side if you aren't moving to the left. It's not beautiful way to do it and I'm sure it's nowhere as good as it should be, but it works. And I can still use the same collision detection to collectibles and enemies where it's not that important what side you collide on.

I'll be sure to check your ways when I get this project done.

Share this post


Link to post
Share on other sites
Quote:
Original post by Asros
I added a variables xdirection and ydirection to the moving funktion. It was so simple. The collision can't happen on left side if you aren't moving to the left. It's not beautiful way to do it and I'm sure it's nowhere as good as it should be, but it works.
I actually suggested that exact solution in my first reply:
Quote:
Original post by jyk
You might also be able to make a good guess at which side the player collided from by examining the player velocity vector
In any case though, I'm glad you got it sorted out :)

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
I actually suggested that exact solution in my first reply:
Quote:
Original post by jyk
You might also be able to make a good guess at which side the player collided from by examining the player velocity vector
In any case though, I'm glad you got it sorted out :)


Well "velocity vector" got me confused. Now that I read it again, it is the same :)

Could be that my brain was trying to point that out to me for the whole night before I got it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this