Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've been learning a bit of collision resolution through a tutorial here and I can't seem to get the AABBvsAABB resolution working, I have CirclevsCircle and AABBvsCircle resolution working with the same method,ResolveCollision

Essentially what happens is I have a test scenario where two AABBs collide with each other. The collision gets detected however, the AABBs will just keep going through each other. If two circles collide, they show the correct response.

If you need the full code you can nab it from my github. This has both Windows and Linux versions.

Here is the data class that is passed to the AABBvsAABB method:

public struct Manifold
{
    public PhysicsObject A, B;
    public float PenetrationDepth;
    public Vector2 Normal;
    public bool AreColliding;
}

Here is the code for testing the collision between the AABB and AABB

public static bool AABBvsAABB (AABB a, AABB b, ref Manifold m)
{
    m.A = a;
    m.B = b;
    m.Normal = b.Position - a.Position;

    //Calculate the extent on the X axis
    float aExtent = (a.Right - a.Left) / 2;
    float bExtent = (b.Right - b.Left) / 2;

    //Find the X overlap
    float xExtent = aExtent + bExtent - Math.Abs (m.Normal.X);

    //SAT Test on X
    if (xExtent > 0) {
        //There was overlap on the X axis, now lets try to Y
        aExtent = (a.Bottom - a.Top) / 2;
        bExtent = (b.Bottom - b.Top) / 2;

        //Calculate Y overlap
        float yExtent = aExtent + bExtent - Math.Abs(m.Normal.Y);

        //SAT Test on Y axis
        if (yExtent > 0){
            //Find which axis has the biggest penetration ;D
            if (xExtent > yExtent){
                if(m.Normal.X < 0)
                    m.Normal = new Vector2(-1,0);
                else
                    m.Normal= Vector2.Zero;
                m.PenetrationDepth = xExtent;   
                m.AreColliding = true;
                return true;
            }
            else {
                if(m.Normal.Y < 0)
                    m.Normal = new Vector2(0,-1);
                else
                    m.Normal= Vector2.Zero;
                m.PenetrationDepth = yExtent;
                m.AreColliding = true;
                return true;
            }
        }
    }
    return false;
}

Lastly here is the ResolveCollision Method.

public static void ResolveCollision(Manifold m)
{
    Vector2 relVelocity = m.B.Velocity - m.A.Velocity;
    //Finds out if the objects are moving towards each other.
    //We only need to resolve collisions that are moving towards, not away.
    float velAlongNormal = PhysicsMath.DotProduct(relVelocity, m.Normal);
    if (velAlongNormal > 0)
        return;
    float e = Math.Min(m.A.Restitution, m.B.Restitution);

    float j = -(1 + e)*velAlongNormal;
    j /= m.A.InvertedMass + m.B.InvertedMass;

    Vector2 impulse = j*m.Normal;
    m.A.Velocity -= m.A.InvertedMass*impulse;
    m.B.Velocity += m.B.InvertedMass*impulse;
}
share|improve this question
    
Normally AABBs are used for collision detection, not for collision resolving. Did you check if those AABBs actually register a collision callback? If not, the resolving codes will never be called. –  laishiekai May 8 '13 at 19:05
    
I did and they do. When I debugged it the ResolveCollision method gets called, but I think there is an issue with how this tutorial calculates the AABBvsAABB normal. I was hoping someone could proofread as the guy who wrote this code certainly didn't .___.''' –  redcodefinal May 8 '13 at 23:22

2 Answers 2

I believe that your manifold normals are incorrect. These AABBs will attempt to "push back" along the axis of the greatest intersection, however:

if(m.Normal.X < 0)
  m.Normal = new Vector2(-1,0);
else
  m.Normal= Vector2.Zero;

That code is saying "if B is further left than A, then the direction to resolve penetration is in the negative X axis, otherwise there is no direction."

Try changing the else block to:

else
  m.Normal = new Vector2( 1, 0 );

However this may still not do quite what you want (if you want the AABB to "bounce" off eachother more naturally.) In that case you will want to just compute the B - A and then normalize the vector. (It should have a method on the class to do so.)

Your resolution does not account for penetration depth either, so you will lose a lot of accuracy at greater timeslices.

share|improve this answer
    
Thanks for the advice. I'm working through Part 2 of that tutorial which deals with timestepping and the like. I'll give your answer a try andsee if it gets fixed. :D –  redcodefinal May 9 '13 at 18:07
    
I figured out what the problem was, I'll post my code for an explanation. Thank you for trying to help. –  redcodefinal May 10 '13 at 2:10
up vote 0 down vote accepted

I fixed the problem by putting a normalized normal into the m.Normal field and multiplied it by a value to flip the normal depending on what axis/axes it was intersecting on.

public static bool TestAABBvsAABB (AABB a, AABB b, ref Manifold m)
        {
            m.A = a;
            m.B = b;
            m.Normal = b.Position - a.Position;

            //Calculate the extent on the X axis
            float aExtent = (a.Right - a.Left) / 2;
            float bExtent = (b.Right - b.Left) / 2;

            //Find the X overlap
            float xExtent = aExtent + bExtent - Math.Abs (m.Normal.X);

            //SAT Test on X
            if (xExtent > 0) {
                //There was overlap on the X axis, now lets try to Y
                aExtent = (a.Bottom - a.Top) / 2;
                bExtent = (b.Bottom - b.Top) / 2;

                //Calculate Y overlap
                float yExtent = aExtent + bExtent - Math.Abs(m.Normal.Y);

                //SAT Test on Y axis
                if (yExtent > 0){
                    //Find which axis has the biggest penetration ;D
                    Vector2 fixnormal;
                    if (xExtent > yExtent){
                        if(m.Normal.X < 0)
                            fixnormal = -Vector2.UnitX;
                        else
                            fixnormal = Vector2.UnitX;

                        m.Normal = PhysicsMath.GetNormal(m.A.Position, m.B.Position) * fixnormal.X;
                        m.PenetrationDepth = xExtent;   
                        m.AreColliding = true;
                        return true;
                    }
                    else {
                        if(m.Normal.Y < 0)
                             fixnormal = -Vector2.UnitY;
                        else
                            fixnormal= Vector2.UnitY;
                        m.Normal = PhysicsMath.GetNormal(m.A.Position, m.B.Position) * fixnormal.Y;
                        m.PenetrationDepth = yExtent;
                        m.AreColliding = true;
                        return true;
                    }
                }
            }

            return false;
        }
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.