public void FinalizeVelocityConstraints()
        {
            for (int i = 0; i < m_constraintCount; ++i)
            {
                b2ContactConstraint c = m_constraints[i];
                b2Manifold          m = c.manifold;

                for (int j = 0; j < c.pointCount; ++j)
                {
                    b2ManifoldPoint          point1 = m.m_points[j];
                    b2ContactConstraintPoint point2 = c.points[j];
                    point1.m_normalImpulse  = point2.normalImpulse;
                    point1.m_tangentImpulse = point2.tangentImpulse;
                }
            }
        }
Beispiel #2
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(b2ManifoldPoint obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
        // Update the contact manifold and touching status.
        // Note: do not assume the fixture AABBs are overlapping or are valid.
        public virtual void Update(b2ContactListener listener)
        {
            oldManifold.CopyFrom(m_manifold);

            // Re-enable this contact.
            Flags |= b2ContactFlags.e_enabledFlag;

            bool touching    = false;
            bool wasTouching = (Flags & b2ContactFlags.e_touchingFlag) == b2ContactFlags.e_touchingFlag;

            bool sensor = FixtureA.m_isSensor || FixtureB.m_isSensor;

            b2Body      bodyA = FixtureA.Body;
            b2Body      bodyB = FixtureB.Body;
            b2Transform xfA   = bodyA.Transform;
            b2Transform xfB   = bodyB.Transform;

            // Is this contact a sensor?
            if (sensor)
            {
                b2Shape shapeA = FixtureA.Shape;
                b2Shape shapeB = FixtureB.Shape;
                touching = b2Collision.b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, ref xfA, ref xfB);

                // Sensors don't generate manifolds.
                m_manifold.pointCount = 0;
            }
            else
            {
                Evaluate(m_manifold, ref xfA, ref xfB);
                touching = m_manifold.pointCount > 0;

                // Match old contact ids to new contact ids and copy the
                // stored impulses to warm start the solver.
                for (int i = 0; i < m_manifold.pointCount; ++i)
                {
                    b2ManifoldPoint mp2 = m_manifold.points[i];
                    mp2.normalImpulse  = 0.0f;
                    mp2.tangentImpulse = 0.0f;
                    b2ContactFeature id2 = mp2.id;

                    for (int j = 0; j < oldManifold.pointCount; ++j)
                    {
                        b2ManifoldPoint mp1 = oldManifold.points[j];

                        if (mp1.id.key == id2.key)
                        {
                            mp2.normalImpulse  = mp1.normalImpulse;
                            mp2.tangentImpulse = mp1.tangentImpulse;
                            break;
                        }
                    }
                }

                if (touching != wasTouching)
                {
                    bodyA.SetAwake(true);
                    bodyB.SetAwake(true);
                }
            }

            if (touching)
            {
                Flags |= b2ContactFlags.e_touchingFlag;
            }
            else
            {
                Flags &= ~b2ContactFlags.e_touchingFlag;
            }

            if (wasTouching == false && touching == true && listener != null)
            {
                listener.BeginContact(this);
            }

            if (wasTouching == true && touching == false && listener != null)
            {
                listener.EndContact(this);
            }

            if (sensor == false && touching && listener != null)
            {
                listener.PreSolve(this, oldManifold);
            }
        }
Beispiel #4
0
        public b2ContactSolver(b2ContactSolverDef def)
        {
            m_step  = def.step;
            m_count = def.count;
            m_positionConstraints = new b2ContactPositionConstraint[m_count];
            for (int pc = 0; pc < m_count; pc++)
            {
                m_positionConstraints[pc] = b2ContactPositionConstraint.Create();
            }

            m_velocityConstraints = new b2ContactVelocityConstraint[m_count];
            for (int vc = 0; vc < m_count; vc++)
            {
                m_velocityConstraints[vc] = b2ContactVelocityConstraint.Create();
            }

            m_positions  = def.positions;
            m_velocities = def.velocities;
            m_contacts   = def.contacts;

            // Initialize position independent portions of the constraints.
            for (int i = 0; i < m_count; ++i)
            {
                b2Contact contact = m_contacts[i];

                b2Fixture  fixtureA = contact.FixtureA;
                b2Fixture  fixtureB = contact.FixtureB;
                b2Shape    shapeA   = fixtureA.Shape;
                b2Shape    shapeB   = fixtureB.Shape;
                float      radiusA  = shapeA.Radius;
                float      radiusB  = shapeB.Radius;
                b2Body     bodyA    = fixtureA.Body;
                b2Body     bodyB    = fixtureB.Body;
                b2Manifold manifold = contact.GetManifold();

                int pointCount = manifold.pointCount;
                Debug.Assert(pointCount > 0);

                b2ContactVelocityConstraint vc = m_velocityConstraints[i];
                vc.friction     = contact.Friction;
                vc.restitution  = contact.Restitution;
                vc.indexA       = bodyA.IslandIndex;
                vc.indexB       = bodyB.IslandIndex;
                vc.invMassA     = bodyA.InvertedMass;
                vc.invMassB     = bodyB.InvertedMass;
                vc.invIA        = bodyA.InvertedI;
                vc.invIB        = bodyB.InvertedI;
                vc.contactIndex = i;
                vc.pointCount   = pointCount;
                vc.K.SetZero();
                vc.normalMass.SetZero();

                b2ContactPositionConstraint pc = m_positionConstraints[i];
                pc.indexA       = bodyA.IslandIndex;
                pc.indexB       = bodyB.IslandIndex;
                pc.invMassA     = bodyA.InvertedMass;
                pc.invMassB     = bodyB.InvertedMass;
                pc.localCenterA = bodyA.Sweep.localCenter;
                pc.localCenterB = bodyB.Sweep.localCenter;
                pc.invIA        = bodyA.InvertedI;
                pc.invIB        = bodyB.InvertedI;
                pc.localNormal  = manifold.localNormal;
                pc.localPoint   = manifold.localPoint;
                pc.pointCount   = pointCount;
                pc.radiusA      = radiusA;
                pc.radiusB      = radiusB;
                pc.type         = manifold.type;

                for (int j = 0; j < pointCount; ++j)
                {
                    b2ManifoldPoint           cp  = manifold.points[j];
                    b2VelocityConstraintPoint vcp = vc.points[j];

                    if (m_step.warmStarting)
                    {
                        vcp.normalImpulse  = m_step.dtRatio * cp.normalImpulse;
                        vcp.tangentImpulse = m_step.dtRatio * cp.tangentImpulse;
                    }
                    else
                    {
                        vcp.normalImpulse  = 0.0f;
                        vcp.tangentImpulse = 0.0f;
                    }

                    vcp.rA.SetZero();
                    vcp.rB.SetZero();
                    vcp.normalMass   = 0.0f;
                    vcp.tangentMass  = 0.0f;
                    vcp.velocityBias = 0.0f;

                    pc.localPoints[j] = cp.localPoint;

                    //vc.points[j] = vcp;
                }

                //Put back the struct data since struct data is copied by value
                //m_positionConstraints[i] = pc;
                //m_velocityConstraints[i] = vc;
            }
        }
        public void Initialize(b2TimeStep step, List <b2Contact> contacts, int contactCount, object allocator)
        {
            b2Contact contact;

            m_step.Set(step);

            m_allocator = allocator;

            int     i;
            b2Vec2  tVec;
            b2Mat22 tMat;

            m_constraintCount = contactCount;

            // fill vector to hold enough constraints
            while (m_constraints.Count < m_constraintCount)
            {
                m_constraints.Add(new b2ContactConstraint());
            }

            for (i = 0; i < contactCount; ++i)
            {
                contact = contacts[i];
                b2Fixture  fixtureA    = contact.m_fixtureA;
                b2Fixture  fixtureB    = contact.m_fixtureB;
                b2Shape    shapeA      = fixtureA.m_shape;
                b2Shape    shapeB      = fixtureB.m_shape;
                float      radiusA     = shapeA.m_radius;
                float      radiusB     = shapeB.m_radius;
                b2Body     bodyA       = fixtureA.m_body;
                b2Body     bodyB       = fixtureB.m_body;
                b2Manifold manifold    = contact.GetManifold();
                float      friction    = b2Settings.b2MixFriction(fixtureA.GetFriction(), fixtureB.GetFriction());;
                float      restitution = b2Settings.b2MixRestitution(fixtureA.GetRestitution(), fixtureB.GetRestitution());

                //var vA:b2Vec2 = bodyA.m_linearVelocity.Copy();
                float vAX = bodyA.m_linearVelocity.x;
                float vAY = bodyA.m_linearVelocity.y;
                //var vB:b2Vec2 = bodyB.m_linearVelocity.Copy();
                float vBX = bodyB.m_linearVelocity.x;
                float vBY = bodyB.m_linearVelocity.y;
                float wA  = bodyA.m_angularVelocity;
                float wB  = bodyB.m_angularVelocity;

                b2Settings.b2Assert(manifold.m_pointCount > 0);

                s_worldManifold.Initialize(manifold, bodyA.m_xf, radiusA, bodyB.m_xf, radiusB);

                float normalX = s_worldManifold.m_normal.x;
                float normalY = s_worldManifold.m_normal.y;

                b2ContactConstraint cc = m_constraints[i];
                cc.bodyA    = bodyA;      //p
                cc.bodyB    = bodyB;      //p
                cc.manifold = manifold;   //p
                //c.normal = normal;
                cc.normal.x   = normalX;
                cc.normal.y   = normalY;
                cc.pointCount = manifold.m_pointCount;
                cc.friction   = friction;
                //-----------------------------修改 2015/12/10 13:07 by kingBook------------------
                float bevel = 10.0f;
                float planeAngle;
                int   vx;
                if (!bodyA.m_allowBevelSlither || bodyA.m_uphillZeroFriction)
                {
                    planeAngle = Mathf.Atan2(normalY, normalX) * 57.3f + 90.0f;
                    vx         = (int)(bodyA.m_linearVelocity.x);
                    if (planeAngle < 0.0f)
                    {
                        planeAngle += 360.0f;
                    }
                    if ((planeAngle > bevel && planeAngle < 90.0f - bevel) || (planeAngle > 180.0f + bevel && planeAngle < 270.0f - bevel))//斜面 左上角-右下角
                    {
                        if (!bodyA.m_allowBevelSlither)
                        {
                            if (vx >= 0.0f)
                            {
                                cc.friction = 1.0f;
                            }
                        }
                        if (bodyA.m_uphillZeroFriction)
                        {
                            if (vx < 0.0f)
                            {
                                cc.friction = 0.0f;
                            }
                        }
                    }
                    else if ((planeAngle > 90.0f && planeAngle < 180.0f - bevel) || (planeAngle > 270.0f + bevel && planeAngle < 360.0f - bevel))//斜面 左下角-右上角
                    {
                        if (!bodyA.m_allowBevelSlither)
                        {
                            if (vx <= 0.0f)
                            {
                                cc.friction = 1.0f;
                            }
                        }
                        if (bodyA.m_uphillZeroFriction)
                        {
                            if (vx > 0.0f)
                            {
                                cc.friction = 0.0f;
                            }
                        }
                    }
                }
                else if (!bodyB.m_allowBevelSlither || bodyB.m_uphillZeroFriction)
                {
                    planeAngle = Mathf.Atan2(-normalY, -normalX) * 57.3f + 90.0f;
                    vx         = (int)(bodyB.m_linearVelocity.x);
                    if (planeAngle < 0.0f)
                    {
                        planeAngle += 360.0f;
                    }
                    if ((planeAngle > bevel && planeAngle < 90.0f - bevel) || (planeAngle > 180.0f + bevel && planeAngle < 270.0f - bevel))//斜面 左上角-右下角
                    {
                        if (!bodyB.m_allowBevelSlither)
                        {
                            if (vx >= 0.0f)
                            {
                                cc.friction = 1.0f;
                            }
                        }
                        if (bodyB.m_uphillZeroFriction)
                        {
                            if (vx < 0.0f)
                            {
                                cc.friction = 0.0f;
                            }
                        }
                    }
                    else if ((planeAngle > 90.0f && planeAngle < 180.0f - bevel) || (planeAngle > 270.0f + bevel && planeAngle < 360.0f - bevel))//斜面 左下角-右上角
                    {
                        if (!bodyB.m_allowBevelSlither)
                        {
                            if (vx <= 0.0f)
                            {
                                cc.friction = 1.0f;
                            }
                        }
                        if (bodyB.m_uphillZeroFriction)
                        {
                            if (vx > 0)
                            {
                                cc.friction = 0.0f;
                            }
                        }
                    }
                }

                if (bodyA.m_isIgnoreFrictionX || bodyB.m_isIgnoreFrictionX)
                {
                    if (Mathf.Abs(normalY) > 0.9f)
                    {
                        cc.friction = 0.0f;
                    }
                }
                else if (bodyA.m_isIgnoreFrictionY || bodyB.m_isIgnoreFrictionY)
                {
                    if (Mathf.Abs(normalX) > 0.9f)
                    {
                        cc.friction = 0.0f;
                    }
                }
                //-----------------------------修改结束------------------
                cc.restitution = restitution;

                cc.localPlaneNormal.x = manifold.m_localPlaneNormal.x;
                cc.localPlaneNormal.y = manifold.m_localPlaneNormal.y;
                cc.localPoint.x       = manifold.m_localPoint.x;
                cc.localPoint.y       = manifold.m_localPoint.y;
                cc.radius             = radiusA + radiusB;
                cc.type = manifold.m_type;

                for (int k = 0; k < cc.pointCount; ++k)
                {
                    b2ManifoldPoint          cp  = manifold.m_points[k];
                    b2ContactConstraintPoint ccp = cc.points[k];

                    ccp.normalImpulse  = cp.m_normalImpulse;
                    ccp.tangentImpulse = cp.m_tangentImpulse;

                    ccp.localPoint.SetV(cp.m_localPoint);

                    float rAX = ccp.rA.x = s_worldManifold.m_points[k].x - bodyA.m_sweep.c.x;
                    float rAY = ccp.rA.y = s_worldManifold.m_points[k].y - bodyA.m_sweep.c.y;
                    float rBX = ccp.rB.x = s_worldManifold.m_points[k].x - bodyB.m_sweep.c.x;
                    float rBY = ccp.rB.y = s_worldManifold.m_points[k].y - bodyB.m_sweep.c.y;

                    float rnA = rAX * normalY - rAY * normalX;            //b2Math.b2Cross(r1, normal);
                    float rnB = rBX * normalY - rBY * normalX;            //b2Math.b2Cross(r2, normal);

                    rnA *= rnA;
                    rnB *= rnB;

                    float kNormal = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rnA + bodyB.m_invI * rnB;
                    //b2Settings.b2Assert(kNormal > Number.MIN_VALUE);
                    ccp.normalMass = 1.0f / kNormal;

                    float kEqualized = bodyA.m_mass * bodyA.m_invMass + bodyB.m_mass * bodyB.m_invMass;
                    kEqualized += bodyA.m_mass * bodyA.m_invI * rnA + bodyB.m_mass * bodyB.m_invI * rnB;
                    //b2Assert(kEqualized > Number.MIN_VALUE);
                    ccp.equalizedMass = 1.0f / kEqualized;

                    //var tangent:b2Vec2 = b2Math.b2CrossVF(normal, 1.0);
                    float tangentX = normalY;
                    float tangentY = -normalX;

                    //var rtA:Number = b2Math.b2Cross(rA, tangent);
                    float rtA = rAX * tangentY - rAY * tangentX;
                    //var rtB:Number = b2Math.b2Cross(rB, tangent);
                    float rtB = rBX * tangentY - rBY * tangentX;

                    rtA *= rtA;
                    rtB *= rtB;

                    float kTangent = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rtA + bodyB.m_invI * rtB;
                    //b2Settings.b2Assert(kTangent > Number.MIN_VALUE);
                    ccp.tangentMass = 1.0f / kTangent;

                    // Setup a velocity bias for restitution.
                    ccp.velocityBias = 0.0f;
                    //b2Dot(c.normal, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
                    float tX = vBX + (-wB * rBY) - vAX - (-wA * rAY);
                    float tY = vBY + (wB * rBX) - vAY - (wA * rAX);
                    //var vRel:Number = b2Dot(cc.normal, t);
                    float vRel = cc.normal.x * tX + cc.normal.y * tY;
                    if (vRel < -b2Settings.b2_velocityThreshold)
                    {
                        ccp.velocityBias += -cc.restitution * vRel;
                    }
                }

                // If we have two points, then prepare the block solver.
                if (cc.pointCount == 2)
                {
                    b2ContactConstraintPoint ccp1 = cc.points[0];
                    b2ContactConstraintPoint ccp2 = cc.points[1];

                    float invMassA = bodyA.m_invMass;
                    float invIA    = bodyA.m_invI;
                    float invMassB = bodyB.m_invMass;
                    float invIB    = bodyB.m_invI;

                    //var rn1A:Number = b2Cross(ccp1.rA, normal);
                    //var rn1B:Number = b2Cross(ccp1.rB, normal);
                    //var rn2A:Number = b2Cross(ccp2.rA, normal);
                    //var rn2B:Number = b2Cross(ccp2.rB, normal);
                    float rn1A = ccp1.rA.x * normalY - ccp1.rA.y * normalX;
                    float rn1B = ccp1.rB.x * normalY - ccp1.rB.y * normalX;
                    float rn2A = ccp2.rA.x * normalY - ccp2.rA.y * normalX;
                    float rn2B = ccp2.rB.x * normalY - ccp2.rB.y * normalX;

                    float k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B;
                    float k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B;
                    float k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B;

                    // Ensure a reasonable condition number.
                    float k_maxConditionNumber = 100.0f;
                    if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
                    {
                        // K is safe to invert.
                        cc.K.col1.Set(k11, k12);
                        cc.K.col2.Set(k12, k22);
                        cc.K.GetInverse(cc.normalMass);
                    }
                    else
                    {
                        // The constraints are redundant, just use one.
                        // TODO_ERIN use deepest?
                        cc.pointCount = 1;
                    }
                }
            }

            //b2Settings.b2Assert(count == m_constraintCount);
        }
Beispiel #6
0
    public b2ContactSolver(b2ContactSolverDef def)
    {
        m_step  = def.step;
        m_count = def.count;
        m_positionConstraints = Arrays.InitializeWithDefaultInstances <b2ContactPositionConstraint>(m_count);
        m_velocityConstraints = Arrays.InitializeWithDefaultInstances <b2ContactVelocityConstraint>(m_count);
        m_positions           = def.positions;
        m_velocities          = def.velocities;
        m_contacts            = def.contacts;

        // Initialize position independent portions of the constraints.
        for (int i = 0; i < m_count; ++i)
        {
            b2Contact contact = m_contacts[i];

            b2Fixture  fixtureA = contact.m_fixtureA;
            b2Fixture  fixtureB = contact.m_fixtureB;
            b2Shape    shapeA   = fixtureA.GetShape();
            b2Shape    shapeB   = fixtureB.GetShape();
            float      radiusA  = shapeA.m_radius;
            float      radiusB  = shapeB.m_radius;
            b2Body     bodyA    = fixtureA.GetBody();
            b2Body     bodyB    = fixtureB.GetBody();
            b2Manifold manifold = contact.GetManifold();

            int pointCount = manifold.pointCount;
            Debug.Assert(pointCount > 0);

            b2ContactVelocityConstraint vc = m_velocityConstraints[i];
            vc.friction     = contact.m_friction;
            vc.restitution  = contact.m_restitution;
            vc.tangentSpeed = contact.m_tangentSpeed;
            vc.indexA       = bodyA.m_islandIndex;
            vc.indexB       = bodyB.m_islandIndex;
            vc.invMassA     = bodyA.m_invMass;
            vc.invMassB     = bodyB.m_invMass;
            vc.invIA        = bodyA.m_invI;
            vc.invIB        = bodyB.m_invI;
            vc.contactIndex = i;
            vc.pointCount   = pointCount;
            vc.K.SetZero();
            vc.normalMass.SetZero();

            b2ContactPositionConstraint pc = m_positionConstraints[i];
            pc.indexA       = bodyA.m_islandIndex;
            pc.indexB       = bodyB.m_islandIndex;
            pc.invMassA     = bodyA.m_invMass;
            pc.invMassB     = bodyB.m_invMass;
            pc.localCenterA = bodyA.m_sweep.localCenter;
            pc.localCenterB = bodyB.m_sweep.localCenter;
            pc.invIA        = bodyA.m_invI;
            pc.invIB        = bodyB.m_invI;
            pc.localNormal  = manifold.localNormal;
            pc.localPoint   = manifold.localPoint;
            pc.pointCount   = pointCount;
            pc.radiusA      = radiusA;
            pc.radiusB      = radiusB;
            pc.type         = manifold.type;

            for (int j = 0; j < pointCount; ++j)
            {
                b2ManifoldPoint           cp  = manifold.points[j];
                b2VelocityConstraintPoint vcp = vc.points[j];

                if (m_step.warmStarting)
                {
                    vcp.normalImpulse  = m_step.dtRatio * cp.normalImpulse;
                    vcp.tangentImpulse = m_step.dtRatio * cp.tangentImpulse;
                }
                else
                {
                    vcp.normalImpulse  = 0.0f;
                    vcp.tangentImpulse = 0.0f;
                }

                vcp.rA.SetZero();
                vcp.rB.SetZero();
                vcp.normalMass   = 0.0f;
                vcp.tangentMass  = 0.0f;
                vcp.velocityBias = 0.0f;

                pc.localPoints[j] = cp.localPoint;
            }
        }
    }
Beispiel #7
0
    // Algorithm:
    // 1. Classify v1 and v2
    // 2. Classify polygon centroid as front or back
    // 3. Flip normal if necessary
    // 4. Initialize normal range to [-pi, pi] about face normal
    // 5. Adjust normal range according to adjacent edges
    // 6. Visit each separating axes, only accept axes within the range
    // 7. Return if _any_ axis indicates separation
    // 8. Clip
    public void Collide(b2Manifold manifold, b2EdgeShape edgeA, b2Transform xfA, b2PolygonShape polygonB, b2Transform xfB)
    {
        m_xf = Utils.b2MulT(xfA, xfB);

        m_centroidB = Utils.b2Mul(m_xf, polygonB.m_centroid);

        m_v0 = edgeA.m_vertex0;
        m_v1 = edgeA.m_vertex1;
        m_v2 = edgeA.m_vertex2;
        m_v3 = edgeA.m_vertex3;

        bool hasVertex0 = edgeA.m_hasVertex0;
        bool hasVertex3 = edgeA.m_hasVertex3;

        b2Vec2 edge1 = m_v2 - m_v1;

        edge1.Normalize();
        m_normal1.Set(edge1.y, -edge1.x);
        float offset1 = Utils.b2Dot(m_normal1, m_centroidB - m_v1);
        float offset0 = 0.0f;
        float offset2 = 0.0f;
        bool  convex1 = false;
        bool  convex2 = false;

        // Is there a preceding edge?
        if (hasVertex0)
        {
            b2Vec2 edge0 = m_v1 - m_v0;
            edge0.Normalize();
            m_normal0.Set(edge0.y, -edge0.x);
            convex1 = Utils.b2Cross(edge0, edge1) >= 0.0f;
            offset0 = Utils.b2Dot(m_normal0, m_centroidB - m_v0);
        }

        // Is there a following edge?
        if (hasVertex3)
        {
            b2Vec2 edge2 = m_v3 - m_v2;
            edge2.Normalize();
            m_normal2.Set(edge2.y, -edge2.x);
            convex2 = Utils.b2Cross(edge1, edge2) > 0.0f;
            offset2 = Utils.b2Dot(m_normal2, m_centroidB - m_v2);
        }

        // Determine front or back collision. Determine collision normal limits.
        if (hasVertex0 && hasVertex3)
        {
            if (convex1 && convex2)
            {
                m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal0;
                    m_upperLimit = m_normal2;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal1;
                    m_upperLimit = -m_normal1;
                }
            }
            else if (convex1)
            {
                m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal0;
                    m_upperLimit = m_normal1;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal2;
                    m_upperLimit = -m_normal1;
                }
            }
            else if (convex2)
            {
                m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal1;
                    m_upperLimit = m_normal2;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal1;
                    m_upperLimit = -m_normal0;
                }
            }
            else
            {
                m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal1;
                    m_upperLimit = m_normal1;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal2;
                    m_upperLimit = -m_normal0;
                }
            }
        }
        else if (hasVertex0)
        {
            if (convex1)
            {
                m_front = offset0 >= 0.0f || offset1 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal0;
                    m_upperLimit = -m_normal1;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = m_normal1;
                    m_upperLimit = -m_normal1;
                }
            }
            else
            {
                m_front = offset0 >= 0.0f && offset1 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = m_normal1;
                    m_upperLimit = -m_normal1;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = m_normal1;
                    m_upperLimit = -m_normal0;
                }
            }
        }
        else if (hasVertex3)
        {
            if (convex2)
            {
                m_front = offset1 >= 0.0f || offset2 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = -m_normal1;
                    m_upperLimit = m_normal2;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal1;
                    m_upperLimit = m_normal1;
                }
            }
            else
            {
                m_front = offset1 >= 0.0f && offset2 >= 0.0f;
                if (m_front)
                {
                    m_normal     = m_normal1;
                    m_lowerLimit = -m_normal1;
                    m_upperLimit = m_normal1;
                }
                else
                {
                    m_normal     = -m_normal1;
                    m_lowerLimit = -m_normal2;
                    m_upperLimit = m_normal1;
                }
            }
        }
        else
        {
            m_front = offset1 >= 0.0f;
            if (m_front)
            {
                m_normal     = m_normal1;
                m_lowerLimit = -m_normal1;
                m_upperLimit = -m_normal1;
            }
            else
            {
                m_normal     = -m_normal1;
                m_lowerLimit = m_normal1;
                m_upperLimit = m_normal1;
            }
        }

        // Get polygonB in frameA
        m_polygonB.count = polygonB.m_count;
        for (int i = 0; i < polygonB.m_count; ++i)
        {
            m_polygonB.vertices[i] = Utils.b2Mul(m_xf, polygonB.m_vertices[i]);
            m_polygonB.normals[i]  = Utils.b2Mul(m_xf.q, polygonB.m_normals[i]);
        }

        m_radius = polygonB.m_radius + edgeA.m_radius;

        manifold.pointCount = 0;

        b2EPAxis edgeAxis = ComputeEdgeSeparation();

        // If no valid normal can be found than this edge should not collide.
        if (edgeAxis.type == b2EPAxis.Type.e_unknown)
        {
            return;
        }

        if (edgeAxis.separation > m_radius)
        {
            return;
        }

        b2EPAxis polygonAxis = ComputePolygonSeparation();

        if (polygonAxis.type != b2EPAxis.Type.e_unknown && polygonAxis.separation > m_radius)
        {
            return;
        }

        // Use hysteresis for jitter reduction.
        const float k_relativeTol = 0.98f;
        const float k_absoluteTol = 0.001f;

        b2EPAxis primaryAxis = new b2EPAxis();

        if (polygonAxis.type == b2EPAxis.Type.e_unknown)
        {
            primaryAxis = edgeAxis;
        }
        else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
        {
            primaryAxis = polygonAxis;
        }
        else
        {
            primaryAxis = edgeAxis;
        }

        b2ClipVertex[]  ie = Arrays.InitializeWithDefaultInstances <b2ClipVertex>(2);
        b2ReferenceFace rf = new b2ReferenceFace();

        if (primaryAxis.type == b2EPAxis.Type.e_edgeA)
        {
            manifold.type = b2Manifold.Type.e_faceA;

            // Search for the polygon normal that is most anti-parallel to the edge normal.
            int   bestIndex = 0;
            float bestValue = Utils.b2Dot(m_normal, m_polygonB.normals[0]);
            for (int i = 1; i < m_polygonB.count; ++i)
            {
                float value = Utils.b2Dot(m_normal, m_polygonB.normals[i]);
                if (value < bestValue)
                {
                    bestValue = value;
                    bestIndex = i;
                }
            }

            int i1 = bestIndex;
            int i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;

            ie[0].v            = m_polygonB.vertices[i1];
            ie[0].id.cf.indexA = 0;
            ie[0].id.cf.indexB = (byte)i1;
            ie[0].id.cf.typeA  = (int)b2ContactFeature.Type.e_face;
            ie[0].id.cf.typeB  = (int)b2ContactFeature.Type.e_vertex;

            ie[1].v            = m_polygonB.vertices[i2];
            ie[1].id.cf.indexA = 0;
            ie[1].id.cf.indexB = (byte)i2;
            ie[1].id.cf.typeA  = (int)b2ContactFeature.Type.e_face;
            ie[1].id.cf.typeB  = (int)b2ContactFeature.Type.e_vertex;

            if (m_front)
            {
                rf.i1     = 0;
                rf.i2     = 1;
                rf.v1     = m_v1;
                rf.v2     = m_v2;
                rf.normal = m_normal1;
            }
            else
            {
                rf.i1     = 1;
                rf.i2     = 0;
                rf.v1     = m_v2;
                rf.v2     = m_v1;
                rf.normal = -m_normal1;
            }
        }
        else
        {
            manifold.type = b2Manifold.Type.e_faceB;

            ie[0].v            = m_v1;
            ie[0].id.cf.indexA = 0;
            ie[0].id.cf.indexB = (byte)primaryAxis.index;
            ie[0].id.cf.typeA  = (int)b2ContactFeature.Type.e_vertex;
            ie[0].id.cf.typeB  = (int)b2ContactFeature.Type.e_face;

            ie[1].v            = m_v2;
            ie[1].id.cf.indexA = 0;
            ie[1].id.cf.indexB = (byte)primaryAxis.index;
            ie[1].id.cf.typeA  = (int)b2ContactFeature.Type.e_vertex;
            ie[1].id.cf.typeB  = (int)b2ContactFeature.Type.e_face;

            rf.i1     = primaryAxis.index;
            rf.i2     = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
            rf.v1     = m_polygonB.vertices[rf.i1];
            rf.v2     = m_polygonB.vertices[rf.i2];
            rf.normal = m_polygonB.normals[rf.i1];
        }

        rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
        rf.sideNormal2 = -rf.sideNormal1;
        rf.sideOffset1 = Utils.b2Dot(rf.sideNormal1, rf.v1);
        rf.sideOffset2 = Utils.b2Dot(rf.sideNormal2, rf.v2);

        // Clip incident edge against extruded edge1 side edges.
        b2ClipVertex[] clipPoints1 = Arrays.InitializeWithDefaultInstances <b2ClipVertex>(2);
        b2ClipVertex[] clipPoints2 = Arrays.InitializeWithDefaultInstances <b2ClipVertex>(2);
        int            np;

        // Clip to box side 1
        np = Utils.b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);

        if (np < Settings.b2_maxManifoldPoints)
        {
            return;
        }

        // Clip to negative box side 1
        np = Utils.b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);

        if (np < Settings.b2_maxManifoldPoints)
        {
            return;
        }

        // Now clipPoints2 contains the clipped points.
        if (primaryAxis.type == b2EPAxis.Type.e_edgeA)
        {
            manifold.localNormal = rf.normal;
            manifold.localPoint  = rf.v1;
        }
        else
        {
            manifold.localNormal = polygonB.m_normals[rf.i1];
            manifold.localPoint  = polygonB.m_vertices[rf.i1];
        }

        int pointCount = 0;

        for (int i = 0; i < Settings.b2_maxManifoldPoints; ++i)
        {
            float separation;

            separation = Utils.b2Dot(rf.normal, clipPoints2[i].v - rf.v1);

            if (separation <= m_radius)
            {
                b2ManifoldPoint cp = manifold.points[pointCount];

                if (primaryAxis.type == b2EPAxis.Type.e_edgeA)
                {
                    cp.localPoint = Utils.b2MulT(m_xf, clipPoints2[i].v);
                    cp.id         = clipPoints2[i].id;
                }
                else
                {
                    cp.localPoint   = clipPoints2[i].v;
                    cp.id.cf.typeA  = clipPoints2[i].id.cf.typeB;
                    cp.id.cf.typeB  = clipPoints2[i].id.cf.typeA;
                    cp.id.cf.indexA = clipPoints2[i].id.cf.indexB;
                    cp.id.cf.indexB = clipPoints2[i].id.cf.indexA;
                }

                ++pointCount;
            }
        }

        manifold.pointCount = pointCount;
    }
Beispiel #8
0
    // Update the contact manifold and touching status.
    // Note: do not assume the fixture AABBs are overlapping or are valid.
    internal void Update(b2ContactListener listener)
    {
        b2Manifold oldManifold = m_manifold;

        // Re-enable this contact.
        m_flags |= ContactFlags.e_enabledFlag;

        bool touching    = false;
        bool wasTouching = (m_flags & ContactFlags.e_touchingFlag) == ContactFlags.e_touchingFlag;

        bool sensorA = m_fixtureA.IsSensor();
        bool sensorB = m_fixtureB.IsSensor();
        bool sensor  = sensorA || sensorB;

        b2Body      bodyA = m_fixtureA.GetBody();
        b2Body      bodyB = m_fixtureB.GetBody();
        b2Transform xfA   = bodyA.GetTransform();
        b2Transform xfB   = bodyB.GetTransform();

        // Is this contact a sensor?
        if (sensor)
        {
            b2Shape shapeA = m_fixtureA.GetShape();
            b2Shape shapeB = m_fixtureB.GetShape();
            touching = Utils.b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB);

            // Sensors don't generate manifolds.
            m_manifold.pointCount = 0;
        }
        else
        {
            Evaluate(m_manifold, xfA, xfB);
            touching = m_manifold.pointCount > 0;

            // Match old contact ids to new contact ids and copy the
            // stored impulses to warm start the solver.
            for (int i = 0; i < m_manifold.pointCount; ++i)
            {
                b2ManifoldPoint mp2 = m_manifold.points[i];
                mp2.normalImpulse  = 0.0f;
                mp2.tangentImpulse = 0.0f;
                b2ContactID id2 = mp2.id;

                for (int j = 0; j < oldManifold.pointCount; ++j)
                {
                    b2ManifoldPoint mp1 = oldManifold.points[j];

                    if (mp1.id.key == id2.key)
                    {
                        mp2.normalImpulse  = mp1.normalImpulse;
                        mp2.tangentImpulse = mp1.tangentImpulse;
                        break;
                    }
                }
            }

            if (touching != wasTouching)
            {
                bodyA.SetAwake(true);
                bodyB.SetAwake(true);
            }
        }

        if (touching)
        {
            m_flags |= ContactFlags.e_touchingFlag;
        }
        else
        {
            m_flags &= ~ContactFlags.e_touchingFlag;
        }

        if (wasTouching == false && touching == true && listener != null)
        {
            listener.BeginContact(this);
        }

        if (wasTouching == true && touching == false && listener != null)
        {
            listener.EndContact(this);
        }

        if (sensor == false && touching && listener != null)
        {
            listener.PreSolve(this, oldManifold);
        }
    }
Beispiel #9
0
        public void Update(b2ContactListener listener)
        {
            // Swap old & new manifold
            b2Manifold tManifold = m_oldManifold;

            m_oldManifold = m_manifold;
            m_manifold    = tManifold;

            // Re-enable this contact
            m_flags |= e_enabledFlag;

            bool touching    = false;
            bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;

            b2Body bodyA = m_fixtureA.m_body;
            b2Body bodyB = m_fixtureB.m_body;

            bool aabbOverlap = m_fixtureA.m_aabb.TestOverlap(m_fixtureB.m_aabb);

            // Is this contat a sensor?
            if ((m_flags & e_sensorFlag) > 0)
            {
                if (aabbOverlap)
                {
                    b2Shape     shapeA = m_fixtureA.GetShape();
                    b2Shape     shapeB = m_fixtureB.GetShape();
                    b2Transform xfA    = bodyA.GetTransform();
                    b2Transform xfB    = bodyB.GetTransform();
                    touching = b2Shape.TestOverlap(shapeA, xfA, shapeB, xfB);
                }

                // Sensors don't generate manifolds
                m_manifold.m_pointCount = 0;
            }
            else
            {
                // Slow contacts don't generate TOI events.
                if (bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet())
                {
                    m_flags |= e_continuousFlag;
                }
                else
                {
                    m_flags &= ~e_continuousFlag;
                }

                if (aabbOverlap)
                {
                    Evaluate();

                    touching = m_manifold.m_pointCount > 0;

                    // Match old contact ids to new contact ids and copy the
                    // stored impulses to warm start the solver.
                    for (int i = 0; i < m_manifold.m_pointCount; ++i)
                    {
                        b2ManifoldPoint mp2 = m_manifold.m_points[i];
                        mp2.m_normalImpulse  = 0.0f;
                        mp2.m_tangentImpulse = 0.0f;
                        b2ContactID id2 = mp2.m_id;

                        for (int j = 0; j < m_oldManifold.m_pointCount; ++j)
                        {
                            b2ManifoldPoint mp1 = m_oldManifold.m_points[j];

                            if (mp1.m_id.key == id2.key)
                            {
                                mp2.m_normalImpulse  = mp1.m_normalImpulse;
                                mp2.m_tangentImpulse = mp1.m_tangentImpulse;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    m_manifold.m_pointCount = 0;
                }
                if (touching != wasTouching)
                {
                    bodyA.SetAwake(true);
                    bodyB.SetAwake(true);
                }
            }

            if (touching)
            {
                m_flags |= e_touchingFlag;
            }
            else
            {
                m_flags &= ~e_touchingFlag;
            }

            if (wasTouching == false && touching == true)
            {
                listener.BeginContact(this);
            }

            if (wasTouching == true && touching == false)
            {
                listener.EndContact(this);
            }

            if ((m_flags & e_sensorFlag) == 0)
            {
                listener.PreSolve(this, m_oldManifold);
            }
        }