I am trying to create a 2D platformer (Mario-type) and I have some problems with collision handling correctly. I am writing this game in C ++ using the SDL for input, image upload, font download, etc. I also use OpenGL through the FreeGLUT library along with SDL to display graphics.
My collision detection method is AABB (Axis-Aligned Bounding Box), and that's really all I need to get started. I need a simple way to determine which side of the collision occurred and how to deal with conflicts. So basically, if the player is facing the top of the platform, move him to the top; if there is a collision with the sides, move the player back towards the object; if there is a collision at the bottom, move the player under the platform.
I tried to use many different ways to do this, for example, try to find the depth of penetration and move the player back along the depth of penetration. Unfortunately, nothing I tried seems to work correctly. The player’s movement ends very confused and repositioning the player when I don’t want it. Part of the reason, probably because I feel that it is something so simple, but I think too much about it.
If someone thinks they can help, please take a look at the code below and help me try to improve this if you can. I would like to refrain from using the library to handle this (as I want to learn on my own) or something like 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] && ballPrev.coords[1] < block[i].coords[3] && block[i].coords[3] < ballPrev.coords[3]) { 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 this code means:
The block variable is basically an integer that stores the number of blocks or platforms. I check all the blocks using a for loop, and the number currently being executed by the loop is represented by the integer i. The coordinate system may seem a little strange, so it’s worth explaining. coords [0] represents the x position (left) of the object (where it starts from the x axis). coords [1] represents the y position (at the top) of the object (where it starts on the y axis). coords [2] represents the width of the object plus the coords [0] (right). coords [3] represents the height of the object plus coords [1] (bottom). de2dCheckCollision performs AABB conflict detection. Up is negative y, and down is positive y, as in most games.
Hope I have provided enough information for someone who could help me. If there is something that I forgot, it can be crucial, let me know and I will provide the necessary information. Finally, for those who can help, providing the code will be very helpful and much appreciated.
Thanks again for your help!
Change 2 . I updated my code using a new algorithm that checks where the ball was previously before the collision. Corner cases work correctly on this single platform, and when I have a wall of objects, I can now slide against it correctly. The only remaining problem is that there is a slight trembling effect that happens when I am on the ground, where the ball constantly rises and falls, as if being pulled by gravity, and then the ball returns to the object.
Change Here is the URL of the image that is trying to show the problems that I'm having: http://img8.imageshack.us/img8/4603/collisionproblem.png
If the explanation in the picture does not make much sense, the ball cannot move to the left around the corner of the object if I did not jump over it. However, the ball can move to the right, but it moves to the right of the object during movement, which is not required. This creates a missed movement essentially where it appears when the ball misses half of the object or so when I move to the right. If this does not make sense, ask me and I will try to clarify more.