# 2D Platformer Collision Handling

I am trying to create a 2D platformer (Mario-type) game and I am some having some issues with handling collisions properly. I am writing this game in C++, using SDL for input, image loading, font loading, etcetera. I am also using OpenGL via the FreeGLUT library in conjunction with SDL to display graphics.

My method of collision detection is AABB (Axis-Aligned Bounding Box), which is really all I need to start with. What I need is an easy way to both detect which side the collision occurred on and handle the collisions properly. So, basically, if the player collides with the top of the platform, reposition him to the top; if there is a collision to the sides, reposition the player back to the side of the object; if there is a collision to the bottom, reposition the player under the platform.

I have tried many different ways of doing this, such as trying to find the penetration depth and repositioning the player backwards by the penetration depth. Sadly, nothing I've tried seems to work correctly. Player movement ends up being very glitchy and repositions the player when I don't want it to. Part of the reason is probably because I feel like this is something so simple but I'm over-thinking it.

If anyone thinks they can help, please take a look at the code below and help me try to improve on this if you can. I would like to refrain from using a library to handle this (as I want to learn on my own) or the something like the SAT (Separating Axis Theorem) if at all possible. Thank you in advance for your help!

``````void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;

int up = 0;
int left = 0;
int right = 0;
int down = 0;

if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}

if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ball
{
down = 1;
}

cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;

if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
``````

To explain what some of this code means:

The blocks variable is basically an integer that is storing the amount of blocks, or platforms. I am checking all of the blocks using a for loop, and the number that the loop is currently on is represented by integer i. The coordinate system might seem a little weird, so that's worth explaining. coords[0] represents the x position (left) of the object (where it starts on the x axis). coords[1] represents the y position (top) of the object (where it starts on the y axis). coords[2] represents the width of the object plus coords[0] (right). coords[3] represents the height of the object plus coords[1] (bottom). de2dCheckCollision performs an AABB collision detection. Up is negative y and down is positive y, as it is in most games.

Hopefully I have provided enough information for someone to help me successfully. If there is something I left out that might be crucial, let me know and I'll provide the necessary information. Finally, for anyone who can help, providing code would be very helpful and much appreciated.

Thank you again for your help!

Edit: I have updated my code with a new algorithm that checks where the ball was previously before collision. Corner cases work on that single platform correctly now, but when I have a wall of objects, I keep can really slide against it, but if I move towards the wall while sliding, I pass through it and an essentially now standing on top of a block inside the wall. Also, there is a jittering effect that happens when I am on the ground, where the ball is constantly going up and down.

-
Did you resolve your jitter? If not it's probably an issue where you are moving your character too far, instead of `TheirPos-ourSize +- 1` remove the 1, if that's what you're doing. If you're just not sure how to get that algorithm figured out I'd be more than willing to help, mine is perfect at the moment =] (also what order are you checking the objects in?) – ultifinitus Oct 28 '11 at 17:57

If I understand your code correctly, you compensate for the collision by offsetting the ball by a fixed amount without affecting its velocity. The reason your ball acts jittery is that although its position is corrected based on the collision, its velocity is still aimed at the colliding object. Because of this velocity, the ball is still moving towards the colliding block, and will collide after a few frames offsetting it again.

Perhaps the most simple solution to this is making sure the velocities are reset upon collision, making sure the ball will not move towards the block after being offset.

-

You don't show any code that's handling movement/velocity of the ball. If you don't stop/bounce the ball, then the very next frame your ball will move back into the block, and get "moved" back, so it'll probably get "stuck" on the side of the block.

If this isn't it, if you can more specific on the problems and/or post more code, someone might be able to help better :-)

-
If it helps, I have updated the code and added a new algorithm that now checks where the ball was before the collision has occurred. The only remaining problem is that there is a small jittering effect that happens when I am on the ground, where the ball is constantly going up and down as if it is being pulled by gravity and then the ball falls back into the object again. – defender-zone Mar 2 '11 at 1:20
@defender-zone you don't want to put the ball back to the previous position. Rather calculate the overlap of the ball and the obstacle when a collision occurs and move the ball away from the obstacle by the calculated amount (overlap). – bummzack Mar 2 '11 at 11:10

Well You can always do what I did, however poorly implemented it was on my part, I have a simple method in my "being" class called update_prev_pos(), which does just that, it stores your current position in a struct to look at later. In my collision resolution function I look at the position of the side in question. If the side was previously outside of the object, then that side must be corrected.

I'm using a two pass method to check and resolve collisions. What I would recommend doing is checking all x-axis collisions, then all y-axis collisions, That way you won't get stuck on objects you shouldn't. happy colliding =)

-

Thanks for all of the help, guys, and sorry for the late response.

I have taken all of these ideas into consideration, and they are helped me fix the issue. If anyone is curious to know how I solved the original and full problem, look here on Stack Overflow for the full answer (including explanations on handling collision more properly). The person who answered my question was really generous and provided a diagram, so that should help those who also have this problem.

Thanks to the following people for helping me with this problem:

• DanTup - Danny Tuppeny
• bummzack
• ghostonline
• ultifinitus

I appreciate it very much!

-
I think it's better if you give credit to the people that helped you rather than create your own answer than mark it as the answer. At the very least, give them an upvote. Just my two cent. – DMan Mar 15 '11 at 4:11
That's a good idea; I didn't think about it. I apologize for that, but I don't even have enough reputation to upvote yet. When I get it, though, I will do so. – defender-zone Mar 15 '11 at 4:18
@defender-zone - It's nothing against you. I've taken the liberty and upvoted all the answers for you. – DMan Mar 15 '11 at 4:43
Thank you for doing so. Apparently, just now I have received enough reputation to upvote thanks to your upvote, so I have done so as well. I have also given credit to those who helped in my answer. – defender-zone Mar 15 '11 at 4:47
@defender-zone - Haha, that's pretty sweet. I didn't remember that would be the case! – DMan Mar 15 '11 at 4:58