Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Platform jumping problems with AABB collisions

Diagram

When my AABB physics engine resolves an intersection, it does so by finding the axis where the penetration is smaller, then "push out" the entity on that axis.

Considering the "jumping moving left" example:

  • If velocityX is bigger than velocityY, AABB pushes the entity out on the Y axis, effectively stopping the jump (result: the player stops in mid-air).
  • If velocityX is smaller than velocitY (not shown in diagram), the program works as intended, because AABB pushes the entity out on the X axis.

How can I solve this problem?

Source code:

public void Update()
    {
        Position += Velocity;
        Velocity += World.Gravity;

        List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);

        for (int i = 0; i < toCheck.Count; i++)
        {
            SSSPBody body = toCheck[i];
            body.Test.Color = Color.White;

            if (body != this && body.Static)
            {                   
                float left = (body.CornerMin.X - CornerMax.X);
                float right = (body.CornerMax.X - CornerMin.X);
                float top = (body.CornerMin.Y - CornerMax.Y);
                float bottom = (body.CornerMax.Y - CornerMin.Y);

                if (SSSPUtils.AABBIsOverlapping(this, body))
                {
                    body.Test.Color = Color.Yellow;

                    Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);

                    Position += overlapVector;
                }

                if (SSSPUtils.AABBIsCollidingTop(this, body))
                {                      
                    if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
                        (Position.Y + Height/2f == body.Position.Y - body.Height/2f))
                    {
                        body.Test.Color = Color.Red;
                        Velocity = new Vector2(Velocity.X, 0);

                    }
                }
            }               
        }
    }

    public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
    {
        if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
            return false;

        return true;
    }
    public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
    {
        if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
            return false;

        return true;
    }
    public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
    {
        if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
            return false;

        if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
            return true;

        return false;
    }
    public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
    {
        Vector2 result = new Vector2(0, 0);

        if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
            return result;

        if (Math.Abs(mLeft) < mRight)
            result.X = mLeft;
        else
            result.X = mRight;

        if (Math.Abs(mTop) < mBottom)
            result.Y = mTop;
        else
            result.Y = mBottom;

        if (Math.Abs(result.X) < Math.Abs(result.Y))
            result.Y = 0;
        else
            result.X = 0;

        return result;
    }
like image 528
Vittorio Romeo Avatar asked Nov 14 '22 21:11

Vittorio Romeo


1 Answers

It's hard to read code of other people, but I think this is one possible (purely brainstormed) workaround, although of course I'm not able to test it:

  1. Before the collision detection happens, save the players velocity to some temporary variable.
  2. After you've done your collision response, check if the players X or Y position has been corrected
  3. If X position has been changed, manually reset (as a kind of "safety reset") the players Y velocity to the one that he had before the response.

By the way, what happens with your current code when your players hits the roof while jumping?

like image 59
TravisG Avatar answered Nov 24 '22 01:11

TravisG