2D Platformer Collision Handling

defender-zone
  • 2D Platformer Collision Handling defender-zone

    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.

  • 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 :-)

  • 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!

Tags
c++ opengl 2d collision-detection sdl
Related questions and answers
  • every 3 or 4 X's down in the wall... I hope this is enough explination, Thanks for any Help, and LOOK AT PREVIOUS POST ABOUT COLLISION DETECTION FOR MORE SPECIFIC FUNCTION PROBLEMS otherwise, heres...Alright so i'm making a vertical side scroller where you are an '8' character traveling downward while avoiding my randomly generated walls (the "generation" function) on the left and right sides... from it. As an added touch i have made it so after you collide while traveling down the randomly generated map (or rather as the walls move uppward while your character stays put) the X chars you've

  • be on the depth buffer is 0.0 viewport.MaxDepth = 1; // the farthest an object can be on the depth buffer is 1.0 device-&gt;RSSetViewports(1, &amp;viewport); // set the viewport..., 1.0f)); device-&gt;ClearDepthStencilView(dsv, D3D10_CLEAR_DEPTH, 1.0f, 0); // select which input layout we are using device-&gt;IASetInputLayout(pVertexLayout); // select which primtive... memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy the vertices to the buffer pBuffer-&gt;Unmap(); // create the index buffer out of DWORDs DWORD OurIndices[] = { 0, 1, 2, // side 1

  • () will return a vector3 that has a 0 z component and x and y values from about 2 to roughly 33. Now how on earth can me with a calculator be better than the computer? what am I missing? 0.0f / 720.0f) * 2.0f... = xyCoords.y; m_font-&gt;DrawTextA(NULL, stateStream.str().c_str(), -1, &amp;rct, DT_LEFT|DT_NOCLIP , D3DXCOLOR(1,0,0,1)); This all works perfectly. Where am I going wrong with the first bit of code... (texture coords for the screen go from -1 to 1 in each axis) but headPos has the value of -1.#IND000 in both the x and y. I think this may be because D3DXVec3Project is returning MASSIVE numbers, although I

  • that make really hard to work with when coding some functions that use them. I was thinking of making ie. SimpleMesh and HierarchyMesh objects, which will also require that the renderer can deal with different types of objects in the same scene. I was also thinking about making a MeshNode class and then make a Mesh object that contains them, but then I have some conflict on where to store some data... constructing a node object it's done referencing a pool of structure instances to prevent allocation for 2 equal frames. Also the lights are something that I'm not sure on how to handle as I need

  • this on what I had done there, but modifying it to fit with Ogre. It is working but not correctly and I would like some help to understand what it is I am doing wrong. I have a state system and when... physics properties. I know there will be errors here as I get the items colliding with the ground but not with each other properly. So I would appreciate some input on what I am doing wrong. void... and colliding strangely with the ground. I have tried to capture the effect with the attached image. I would appreciate any help in understanding what I have done wrong. Thanks. EDIT : Solution The following

  • &lt; numTriangles; i++) { MD2Triangle* triangle = triangles + i; for(int j = 0; j &lt; 3; j++) { MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j... NEHE'S TUT glBegin (GL_TRIANGLES); // Tell OpenGL What We Want To Draw for(int i = 0; i &lt; numTriangles; i++) { MD2Triangle* triangle = triangles + i; for(int j = 0; j &lt; 3; j++) { MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j]; MD2Vertex* v2 = frame2-&gt;vertices + triangle-&gt;vertices[j

  • I been working in the animation of a 2D platformer game in C++/SDL/OpenGL, and my team and I reach the point where we need to establish that every animation of the player (Walking, Running, etc... the movement and the changes of frames. To clarify what I mean I have in my Sprite class these parameters: std::vector< Vector2f &gt; delayMovementSprite; std::vector< int &gt; frameDelayPerAnimation...; int frameCount; And in the function that animates I do the following, much like the MoveX in Sprite: int Animation::animate() { if( oldTime + frameRate &gt; SDL_GetTicks() ) { return -1

  • Dear all, this is going to be tough: I have created a game object factory that generates objects of my wish. However, I get memory leaks which I can not fix. Memory leaks are generated by return... true; } Before taking a look at the code below, let me help you in that my CGameObjectFactory creates pointers to functions creating particular object type. The pointers are stored within vFactories vector container. I have chosen this way because I parse an object map file. I have object type IDs (integer values) which I need to translate them into real objects. Because I have over 100

  • areas of concern I have and wanted to get some opinions on the proper way others have solved them or would solve them. 1. Cyclical Dependencies When I was doing the game in C#, I didn't really have...I've been working on a 2d RPG for awhile now, and I've come to realize I've made some bad design decisions. Theres a few things in particular that are causing me problems, so I was wondering what... question about it is, is this a worthwhile approach at all? If it's a bad design I want to know now before I invest too much more time making all the screens I'm going to need. How do you build up

Data information