AABB vs OBB Collision Resolution jitter on corners

Posted by patt4179 on Game Development See other posts from Game Development or by patt4179
Published on 2013-11-06T02:19:59Z Indexed on 2013/11/06 4:20 UTC
Read the original article Hit count: 257

I've implemented a collision library for a character who is an AABB and am resolving collisions between AABB vs AABB and AABB vs OBB. I wanted slopes for certain sections, so I've toyed around with using several OBBs to make one, and it's working great except for one glaring issue; The collision resolution on the corner of an OBB makes the player's AABB jitter up and down constantly. I've tried a few things I've thought of, but I just can't wrap my head around what's going on exactly. Here's a video of what's happening as well as my code:

Here's the function to get the collision resolution (I'm likely not doing this the right way, so this may be where the issue lies):

public Vector2 GetCollisionResolveAmount(RectangleCollisionObject resolvedObject, OrientedRectangleCollisionObject b)
{
    Vector2 overlap = Vector2.Zero;
    LineSegment edge = GetOrientedRectangleEdge(b, 0);


    if (!SeparatingAxisForRectangle(edge, resolvedObject))
    {
        LineSegment rEdgeA = new LineSegment(), rEdgeB = new LineSegment();
        Range axisRange = new Range(), rEdgeARange = new Range(), rEdgeBRange = new Range(), rProjection = new Range();
        Vector2 n = edge.PointA - edge.PointB;

        rEdgeA.PointA = RectangleCorner(resolvedObject, 0);
        rEdgeA.PointB = RectangleCorner(resolvedObject, 1);
        rEdgeB.PointA = RectangleCorner(resolvedObject, 2);
        rEdgeB.PointB = RectangleCorner(resolvedObject, 3);
        rEdgeARange = ProjectLineSegment(rEdgeA, n);
        rEdgeBRange = ProjectLineSegment(rEdgeB, n);
        rProjection = GetRangeHull(rEdgeARange, rEdgeBRange);
        axisRange = ProjectLineSegment(edge, n);

        float axisMid = (axisRange.Maximum + axisRange.Minimum) / 2;
        float projectionMid = (rProjection.Maximum + rProjection.Minimum) / 2;

        if (projectionMid > axisMid)
        {
            overlap.X = axisRange.Maximum - rProjection.Minimum;
        }
        else
        {
            overlap.X = rProjection.Maximum - axisRange.Minimum;
            overlap.X = -overlap.X;
        }
    }

    edge = GetOrientedRectangleEdge(b, 1);
    if (!SeparatingAxisForRectangle(edge, resolvedObject))
    {
        LineSegment rEdgeA = new LineSegment(), rEdgeB = new LineSegment();
        Range axisRange = new Range(), rEdgeARange = new Range(), rEdgeBRange = new Range(), rProjection = new Range();
        Vector2 n = edge.PointA - edge.PointB;

        rEdgeA.PointA = RectangleCorner(resolvedObject, 0);
        rEdgeA.PointB = RectangleCorner(resolvedObject, 1);
        rEdgeB.PointA = RectangleCorner(resolvedObject, 2);
        rEdgeB.PointB = RectangleCorner(resolvedObject, 3);
        rEdgeARange = ProjectLineSegment(rEdgeA, n);
        rEdgeBRange = ProjectLineSegment(rEdgeB, n);
        rProjection = GetRangeHull(rEdgeARange, rEdgeBRange);
        axisRange = ProjectLineSegment(edge, n);

        float axisMid = (axisRange.Maximum + axisRange.Minimum) / 2;
        float projectionMid = (rProjection.Maximum + rProjection.Minimum) / 2;

        if (projectionMid > axisMid)
        {
            overlap.Y = axisRange.Maximum - rProjection.Minimum;
            overlap.Y = -overlap.Y;
        }
        else
        {
            overlap.Y = rProjection.Maximum - axisRange.Minimum;
        }
    }

    return overlap;            
}

And here is what I'm doing to resolve it right now:

if (collisionDetection.OrientedRectangleAndRectangleCollide(obb, player.PlayerCollision))
{
    var resolveAmount = collisionDetection.GetCollisionResolveAmount(player.PlayerCollision, obb);

    if (Math.Abs(resolveAmount.Y) < Math.Abs(resolveAmount.X))
    {
        var roundedAmount = (float)Math.Floor(resolveAmount.Y);
        player.PlayerCollision._position.Y -= roundedAmount;
    }
    else if (Math.Abs(resolveAmount.Y) <= 30.0f) //Catch cases where the player should be able to step over the top of something
    {
        var roundedAmount = (float)Math.Floor(resolveAmount.Y);
        player.PlayerCollision._position.Y -= roundedAmount;
    }
    else
    {
        var roundedAmount = (float)Math.Floor(resolveAmount.X);
        player.PlayerCollision._position.X -= roundedAmount;
    }
}

Can anyone see what might be the issue here, or has anyone experienced this before that knows a possible solution? I've tried for a few days to figure this out on my own, but I'm just stumped.

© Game Development or respective owner

Related posts about collision-resolution

Related posts about separating-axis-theorem