Esempio n. 1
0
        /// <summary>
        /// Destroy a fixture. This removes the fixture from the broad-phase and
        /// destroys all contacts associated with this fixture. This will
        /// automatically adjust the mass of the body if the body is dynamic and the
        /// fixture has positive density.
        /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.
        /// Warning: This function is locked during callbacks.
        /// </summary>
        /// <param name="fixture">The fixture to be removed.</param>
        public void DestroyFixture(Fixture fixture)
        {
            Debug.Assert(fixture.Body == this);

            // Remove the fixture from this body's singly linked list.
            Debug.Assert(FixtureList.Count > 0);

            // You tried to remove a fixture that not present in the fixturelist.
            Debug.Assert(FixtureList.Contains(fixture));

            // Destroy any contacts associated with the fixture.
            ContactEdge edge = ContactList;

            while (edge != null)
            {
                Contact c = edge.Contact;
                edge = edge.Next;

                Fixture fixtureA = c.FixtureA;
                Fixture fixtureB = c.FixtureB;

                if (fixture == fixtureA || fixture == fixtureB)
                {
                    // This destroys the contact and removes it from
                    // this body's contact list.
                    World.ContactManager.Destroy(c);
                }
            }

            if ((Flags & BodyFlags.Enabled) == BodyFlags.Enabled)
            {
                IBroadPhase broadPhase = World.ContactManager.BroadPhase;
                fixture.DestroyProxies(broadPhase);
            }

            FixtureList.Remove(fixture);
            fixture.Destroy();
            fixture.Body = null;

            ResetMassData();
        }
Esempio n. 2
0
        /// <summary>
        /// Destroy a fixture. This removes the fixture from the broad-phase and
        /// destroys all contacts associated with this fixture. This will
        /// automatically adjust the mass of the body if the body is dynamic and the
        /// fixture has positive density.
        /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.
        /// Warning: This function is locked during callbacks.
        /// </summary>
        /// <param name="fixture">The fixture to be removed.</param>
        public void destroyFixture(Fixture fixture)
        {
            Debug.Assert(fixture.body == this);

            // Remove the fixture from this body's singly linked list.
            Debug.Assert(fixtureList.Count > 0);

            // You tried to remove a fixture that not present in the fixturelist.
            Debug.Assert(fixtureList.Contains(fixture));

            // Destroy any contacts associated with the fixture.
            ContactEdge edge = contactList;

            while (edge != null)
            {
                var c = edge.contact;
                edge = edge.next;

                var fixtureA = c.fixtureA;
                var fixtureB = c.fixtureB;

                if (fixture == fixtureA || fixture == fixtureB)
                {
                    // This destroys the contact and removes it from
                    // this body's contact list.
                    _world.contactManager.destroy(c);
                }
            }

            if (_enabled)
            {
                var broadPhase = _world.contactManager.broadPhase;
                fixture.destroyProxies(broadPhase);
            }

            fixtureList.Remove(fixture);
            fixture.destroy();
            fixture.body = null;

            resetMassData();
        }
Esempio n. 3
0
        public ContactEdge Restore(bool restoreLinks, Dictionary <string, TrueSync.Physics2D.Contact> contactDic, Dictionary <string, ContactEdge> contactEdgeDic)
        {
            string      key = this.contactKey + "_" + this.body.BodyId;
            ContactEdge result;

            if (restoreLinks)
            {
                ContactEdge contactEdge = contactEdgeDic[key];
                bool        flag        = this.nextEdge != null;
                if (flag)
                {
                    contactEdge.Next = contactEdgeDic[this.nextEdge];
                }
                bool flag2 = this.previousEdge != null;
                if (flag2)
                {
                    contactEdge.Prev = contactEdgeDic[this.previousEdge];
                }
                result = contactEdge;
            }
            else
            {
                bool flag3 = contactEdgeDic.ContainsKey(key);
                if (flag3)
                {
                    result = contactEdgeDic[key];
                }
                else
                {
                    ContactEdge @new = WorldClone2D.poolContactEdge.GetNew();
                    @new.Contact        = contactDic[this.contactKey];
                    @new.Other          = this.body;
                    contactEdgeDic[key] = @new;
                    result = @new;
                }
            }
            return(result);
        }
Esempio n. 4
0
        private bool AreBodiesColliding(Body bodyA_, Body bodyB_)
        {
            // If either of the bodies are null
            if (bodyA_ == null || bodyB_ == null)
            {
                return(false);
            }

            // If either of the bodies have no contact list
            if (bodyA_.ContactList == null || bodyB_.ContactList == null)
            {
                return(false);
            }

            // Contact point for the body
            ContactEdge ce = bodyA_.ContactList;

            // While there is a valid contact point
            while (ce != null)
            {
                // If the two bodies are colliding (AABB)
                if (ce.Other == bodyB_)
                {
                    Contact c = ce.Contact;
                    // If the two bodies are physically touching
                    if (c.IsTouching && c.Enabled)
                    {
                        return(true);
                    }
                }

                // Get next contact point
                ce = ce.Next;
            }

            // If the two bodies are not colliding
            return(false);
        }
Esempio n. 5
0
        /// <summary>
        /// Call this if you want to establish collision that was previously disabled by
        /// ContactFilter::ShouldCollide.
        /// </summary>
        public void Refilter()
        {
            if (Body == null)
            {
                return;
            }

            // Flag associated contacts for filtering.
            ContactEdge edge = Body.ContactList;

            while (edge != null)
            {
                Contact contact  = edge.Contact;
                Fixture fixtureA = contact.FixtureA;
                Fixture fixtureB = contact.FixtureB;
                if (fixtureA == this || fixtureB == this)
                {
                    contact.SetFlagForFiltering();
                }
                edge = edge.Next;
            }

            World world = Body.World;

            if (world == null)
            {
                return;
            }

            // Touch each proxy so that new pairs may be created
            BroadPhase broadPhase = world.ContactManager.BroadPhase;

            for (int i = 0; i < ProxyCount; ++i)
            {
                broadPhase.TouchProxy(Proxies[i].ProxyId);
            }
        }
Esempio n. 6
0
        /**
         * Call this if you want to establish collision that was previously disabled by
         * ContactFilter::ShouldCollide.
         */

        public void refilter()
        {
            if (m_body == null)
            {
                return;
            }

            // Flag associated contacts for filtering.
            ContactEdge edge = m_body.getContactList();

            while (edge != null)
            {
                Contact contact  = edge.contact;
                Fixture fixtureA = contact.getFixtureA();
                Fixture fixtureB = contact.getFixtureB();
                if (fixtureA == this || fixtureB == this)
                {
                    contact.flagForFiltering();
                }
                edge = edge.next;
            }

            World world = m_body.getWorld();

            if (world == null)
            {
                return;
            }

            // Touch each proxy so that new pairs may be created
            BroadPhase broadPhase = world.m_contactManager.m_broadPhase;

            for (int i = 0; i < m_proxyCount; ++i)
            {
                broadPhase.touchProxy(m_proxies[i].proxyId);
            }
        }
Esempio n. 7
0
        public void AreaAttack()
        {
            ContactEdge c = _body.ContactList;

            while (c != null && c.Next != null)
            {
                if (c.Contact.IsTouching)
                {
                    Entity e = (Entity)c.Other.UserData;
                    if (e.GetComponent <CircleCollider>() != null)
                    {
                        Vector2 force = e.Position - _owner.Position;
                        force.Normalize();
                        force *= m_areaKnockback;
                        e.GetComponent <CircleCollider>().ApplyForce(force, _owner.Position);
                    }
                    if (e.GetComponent <Damageable>() != null)
                    {
                        e.GetComponent <Damageable>().DealDamage(m_areaAttack);
                    }
                }
                c = c.Next;
            }
        }
        /// <summary>
        /// Destroy a joint. This may cause the connected bodies to begin colliding.
        /// Warning: This function is locked during callbacks.
        /// </summary>
        /// <param name="joint">The joint.</param>
        public void RemoveJoint(Joint joint)
        {
            Debug.Assert(!IsLocked);
            if (IsLocked)
            {
                return;
            }

            bool collideConnected = joint.CollideConnected;

            // Remove from the world list.
            JointList.Remove(joint);

            // Disconnect from island graph.
            Body bodyA = joint.BodyA;
            Body bodyB = joint.BodyB;

            // Wake up connected bodies.
            bodyA.Awake = true;

            // WIP David
            if (!joint.IsFixedType())
            {
                bodyB.Awake = true;
            }

            // Remove from body 1.
            if (joint.EdgeA.Prev != null)
            {
                joint.EdgeA.Prev.Next = joint.EdgeA.Next;
            }

            if (joint.EdgeA.Next != null)
            {
                joint.EdgeA.Next.Prev = joint.EdgeA.Prev;
            }

            if (joint.EdgeA == bodyA.JointList)
            {
                bodyA.JointList = joint.EdgeA.Next;
            }

            joint.EdgeA.Prev = null;
            joint.EdgeA.Next = null;

            // WIP David
            if (!joint.IsFixedType())
            {
                // Remove from body 2
                if (joint.EdgeB.Prev != null)
                {
                    joint.EdgeB.Prev.Next = joint.EdgeB.Next;
                }

                if (joint.EdgeB.Next != null)
                {
                    joint.EdgeB.Next.Prev = joint.EdgeB.Prev;
                }

                if (joint.EdgeB == bodyB.JointList)
                {
                    bodyB.JointList = joint.EdgeB.Next;
                }

                joint.EdgeB.Prev = null;
                joint.EdgeB.Next = null;
            }

            // WIP David
            if (!joint.IsFixedType())
            {
                // If the joint prevents collisions, then flag any contacts for filtering.
                if (collideConnected == false)
                {
                    ContactEdge edge = bodyB.ContactList;
                    while (edge != null)
                    {
                        if (edge.Other == bodyA)
                        {
                            // Flag the contact for filtering at the next time step (where either
                            // body is awake).
                            edge.Contact.FlagForFiltering();
                        }

                        edge = edge.Next;
                    }
                }
            }

            if (JointRemoved != null)
            {
                JointRemoved(joint);
            }
        }
Esempio n. 9
0
        /**
         * Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts
         * associated with this fixture. This will automatically adjust the mass of the body if the body
         * is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly
         * destroyed when the body is destroyed.
         *
         * @param fixture the fixture to be removed.
         * @warning This function is locked during callbacks.
         */

        public void destroyFixture(Fixture fixture)
        {
            if (m_world.isLocked())
            {
                return;
            }

            // Remove the fixture from this body's singly linked list.
            Fixture node  = m_fixtureList;
            Fixture last  = null; // java change
            bool    found = false;

            while (node != null)
            {
                if (node == fixture)
                {
                    node  = fixture.m_next;
                    found = true;
                    break;
                }
                last = node;
                node = node.m_next;
            }

            // You tried to remove a shape that is not attached to this body.

            // java change, remove it from the list
            if (last == null)
            {
                m_fixtureList = fixture.m_next;
            }
            else
            {
                last.m_next = fixture.m_next;
            }

            // Destroy any contacts associated with the fixture.
            ContactEdge edge = m_contactList;

            while (edge != null)
            {
                Contact c = edge.contact;
                edge = edge.next;

                Fixture fixtureA = c.getFixtureA();
                Fixture fixtureB = c.getFixtureB();

                if (fixture == fixtureA || fixture == fixtureB)
                {
                    // This destroys the contact and removes it from
                    // this body's contact list.
                    m_world.m_contactManager.destroy(c);
                }
            }

            if ((m_flags & e_activeFlag) == e_activeFlag)
            {
                BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
                fixture.destroyProxies(broadPhase);
            }

            fixture.destroy();
            fixture.m_body = null;
            fixture.m_next = null;
            fixture        = null;

            --m_fixtureCount;

            // Reset the mass data.
            resetMassData();
        }
Esempio n. 10
0
        public Body(BodyDef bd, World world)
        {
            m_flags = 0;

            if (bd.bullet)
            {
                m_flags |= e_bulletFlag;
            }
            if (bd.fixedRotation)
            {
                m_flags |= e_fixedRotationFlag;
            }
            if (bd.allowSleep)
            {
                m_flags |= e_autoSleepFlag;
            }
            if (bd.awake)
            {
                m_flags |= e_awakeFlag;
            }
            if (bd.active)
            {
                m_flags |= e_activeFlag;
            }

            m_world = world;

            m_xf.p.set(bd.position);
            m_xf.q.set(bd.angle);

            m_sweep.localCenter.setZero();
            m_sweep.c0.set(m_xf.p);
            m_sweep.c.set(m_xf.p);
            m_sweep.a0     = bd.angle;
            m_sweep.a      = bd.angle;
            m_sweep.alpha0 = 0.0d;

            m_jointList   = null;
            m_contactList = null;
            m_prev        = null;
            m_next        = null;

            m_linearVelocity.set(bd.linearVelocity);
            m_angularVelocity = bd.angularVelocity;

            m_linearDamping  = bd.linearDamping;
            m_angularDamping = bd.angularDamping;
            m_gravityScale   = bd.gravityScale;

            m_force.setZero();
            m_torque = 0.0d;

            m_sleepTime = 0.0d;

            m_type = bd.type;

            if (m_type == BodyType.DYNAMIC)
            {
                m_mass    = 1d;
                m_invMass = 1d;
            }
            else
            {
                m_mass    = 0d;
                m_invMass = 0d;
            }

            m_I    = 0.0d;
            m_invI = 0.0d;

            m_userData = bd.userData;

            m_fixtureList  = null;
            m_fixtureCount = 0;
        }
Esempio n. 11
0
        private void HandleLimbCollision(Contact contact, Limb limb)
        {
            if (limb.Mass > 100.0f)
            {
                Vector2 normal = Vector2.Normalize(Body.SimPosition - limb.SimPosition);

                float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 50.0f) / 5.0f * Math.Min(limb.Mass / 200.0f, 1);

                ApplyImpact(impact, -normal, contact);
                foreach (Submarine dockedSub in submarine.DockedTo)
                {
                    dockedSub.SubBody.ApplyImpact(impact, -normal, contact);
                }
            }

            //find all contacts between the limb and level walls
            List <Contact> levelContacts = new List <Contact>();
            ContactEdge    contactEdge   = limb.body.FarseerBody.ContactList;

            while (contactEdge.Next != null)
            {
                if (contactEdge.Contact.Enabled &&
                    contactEdge.Other.UserData is VoronoiCell &&
                    contactEdge.Contact.IsTouching)
                {
                    levelContacts.Add(contactEdge.Contact);
                }
                contactEdge = contactEdge.Next;
            }

            if (levelContacts.Count == 0)
            {
                return;
            }

            //if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it
            //not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete),
            //but more realistic than bouncing and prevents using characters as "bumpers" that prevent all collision damage

            //TODO: apply impact damage and/or gib the character that got crushed between the sub and the level?
            Vector2 avgContactNormal = Vector2.Zero;

            foreach (Contact levelContact in levelContacts)
            {
                Vector2 contactNormal;
                FixedArray2 <Vector2> temp;
                levelContact.GetWorldManifold(out contactNormal, out temp);

                //if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal
                VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
                                   ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);

                var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center;
                if (Vector2.Dot(contactNormal, cellDiff) < 0)
                {
                    contactNormal = -contactNormal;
                }

                avgContactNormal += contactNormal;

                //apply impacts at the positions where this sub is touching the limb
                ApplyImpact((Vector2.Dot(-Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, levelContact);
            }
            avgContactNormal /= levelContacts.Count;

            float contactDot = Vector2.Dot(Body.LinearVelocity, -avgContactNormal);

            if (contactDot > 0.0f)
            {
                Body.LinearVelocity -= Vector2.Normalize(Body.LinearVelocity) * contactDot;

                float damageAmount = contactDot * Body.Mass / limb.character.Mass;

                Vector2 n;
                FixedArray2 <Vector2> contactPos;
                contact.GetWorldManifold(out n, out contactPos);
                limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(contactPos[0]), limb, DamageType.Blunt, damageAmount, 0.0f, 0.0f, true, 0.0f);

                if (limb.character.IsDead)
                {
                    foreach (LimbJoint limbJoint in limb.character.AnimController.LimbJoints)
                    {
                        if (limbJoint.IsSevered || (limbJoint.LimbA != limb && limbJoint.LimbB != limb))
                        {
                            continue;
                        }
                        limb.character.AnimController.SeverLimbJoint(limbJoint);
                    }
                }
            }
        }
Esempio n. 12
0
        // Broad-phase callback.
        private void AddPair(int proxyIdA, int proxyIdB)
        {
            FixtureProxy proxyA = BroadPhase.GetProxy(proxyIdA);
            FixtureProxy proxyB = BroadPhase.GetProxy(proxyIdB);

            Fixture fixtureA = proxyA.Fixture;
            Fixture fixtureB = proxyB.Fixture;

            int indexA = proxyA.ChildIndex;
            int indexB = proxyB.ChildIndex;

            Body bodyA = fixtureA.Body;
            Body bodyB = fixtureB.Body;

            // Are the fixtures on the same body?
            if (bodyA == bodyB)
            {
                return;
            }

            // Does a contact already exist?
            for (ContactEdge ceB = bodyB.ContactList; ceB != null; ceB = ceB.Next)
            {
                if (ceB.Other == bodyA)
                {
                    Fixture fA = ceB.Contact.FixtureA;
                    Fixture fB = ceB.Contact.FixtureB;
                    int     iA = ceB.Contact.ChildIndexA;
                    int     iB = ceB.Contact.ChildIndexB;

                    if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
                    {
                        // A contact already exists.
                        return;
                    }

                    if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
                    {
                        // A contact already exists.
                        return;
                    }
                }
            }

            // Does a joint override collision? Is at least one body dynamic?
            if (bodyB.ShouldCollide(bodyA) == false)
            {
                return;
            }

            //Check default filter
            if (ShouldCollide(fixtureA, fixtureB) == false)
            {
                return;
            }

            // Check user filtering.
            var contactFilterHandler = ContactFilter;

            if (contactFilterHandler != null)
            {
                if (contactFilterHandler(fixtureA, fixtureB) == false)
                {
                    return;
                }
            }

            //FPE feature: BeforeCollision delegate
            var beforeCollisionHandlerA = fixtureA.BeforeCollision;

            if (beforeCollisionHandlerA != null)
            {
                if (beforeCollisionHandlerA(fixtureA, fixtureB) == false)
                {
                    return;
                }
            }

            var beforeCollisionHandlerB = fixtureB.BeforeCollision;

            if (beforeCollisionHandlerB != null)
            {
                if (beforeCollisionHandlerB(fixtureB, fixtureA) == false)
                {
                    return;
                }
            }

            // Call the factory.
            Contact c = Contact.Create(this, fixtureA, indexA, fixtureB, indexB);

            if (c == null)
            {
                return;
            }

            // Contact creation may swap fixtures.
            fixtureA = c.FixtureA;
            fixtureB = c.FixtureB;
            bodyA    = fixtureA.Body;
            bodyB    = fixtureB.Body;

            // Insert into the world.
            c.Prev      = ContactList;
            c.Next      = c.Prev.Next;
            c.Prev.Next = c;
            c.Next.Prev = c;
            ContactCount++;

#if USE_ACTIVE_CONTACT_SET
            ActiveContacts.Add(c);
#endif
            // Connect to island graph.

            // Connect to body A
            c._nodeA.Contact = c;
            c._nodeA.Other   = bodyB;

            c._nodeA.Prev = null;
            c._nodeA.Next = bodyA.ContactList;
            if (bodyA.ContactList != null)
            {
                bodyA.ContactList.Prev = c._nodeA;
            }
            bodyA.ContactList = c._nodeA;

            // Connect to body B
            c._nodeB.Contact = c;
            c._nodeB.Other   = bodyA;

            c._nodeB.Prev = null;
            c._nodeB.Next = bodyB.ContactList;
            if (bodyB.ContactList != null)
            {
                bodyB.ContactList.Prev = c._nodeB;
            }
            bodyB.ContactList = c._nodeB;

            // Wake up the bodies
            if (fixtureA.IsSensor == false && fixtureB.IsSensor == false)
            {
                bodyA.Awake = true;
                bodyB.Awake = true;
            }
        }
Esempio n. 13
0
        private void HandleLimbCollision(Impact collision, Limb limb)
        {
            if (limb?.body?.FarseerBody == null || limb.character == null)
            {
                return;
            }

            if (limb.Mass > MinImpactLimbMass)
            {
                Vector2 normal =
                    Vector2.DistanceSquared(Body.SimPosition, limb.SimPosition) < 0.0001f ?
                    Vector2.UnitY :
                    Vector2.Normalize(Body.SimPosition - limb.SimPosition);

                float impact = Math.Min(Vector2.Dot(collision.Velocity, -normal), 50.0f) * Math.Min(limb.Mass / 100.0f, 1);

                ApplyImpact(impact, -normal, collision.ImpactPos, applyDamage: false);
                foreach (Submarine dockedSub in submarine.DockedTo)
                {
                    dockedSub.SubBody.ApplyImpact(impact, -normal, collision.ImpactPos, applyDamage: false);
                }
            }

            //find all contacts between the limb and level walls
            List <Contact> levelContacts = new List <Contact>();
            ContactEdge    contactEdge   = limb.body.FarseerBody.ContactList;

            while (contactEdge?.Contact != null)
            {
                if (contactEdge.Contact.Enabled &&
                    contactEdge.Contact.IsTouching &&
                    contactEdge.Other?.UserData is VoronoiCell)
                {
                    levelContacts.Add(contactEdge.Contact);
                }
                contactEdge = contactEdge.Next;
            }

            if (levelContacts.Count == 0)
            {
                return;
            }

            //if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it
            //not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete),
            //but more realistic than bouncing and prevents using characters as "bumpers" that prevent all collision damage
            Vector2 avgContactNormal = Vector2.Zero;

            foreach (Contact levelContact in levelContacts)
            {
                levelContact.GetWorldManifold(out Vector2 contactNormal, out FixedArray2 <Vector2> temp);

                //if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal
                VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
                                   ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);

                var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center;
                if (Vector2.Dot(contactNormal, cellDiff) < 0)
                {
                    contactNormal = -contactNormal;
                }

                avgContactNormal += contactNormal;

                //apply impacts at the positions where this sub is touching the limb
                ApplyImpact((Vector2.Dot(-collision.Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, collision.ImpactPos, applyDamage: false);
            }
            avgContactNormal /= levelContacts.Count;

            float contactDot = Vector2.Dot(Body.LinearVelocity, -avgContactNormal);

            if (contactDot > 0.001f)
            {
                Vector2 velChange = Vector2.Normalize(Body.LinearVelocity) * contactDot;
                if (!MathUtils.IsValid(velChange))
                {
                    GameAnalyticsManager.AddErrorEventOnce(
                        "SubmarineBody.HandleLimbCollision:" + submarine.ID,
                        GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                        "Invalid velocity change in SubmarineBody.HandleLimbCollision (submarine velocity: " + Body.LinearVelocity
                        + ", avgContactNormal: " + avgContactNormal
                        + ", contactDot: " + contactDot
                        + ", velChange: " + velChange + ")");
                    return;
                }

                Body.LinearVelocity -= velChange;

                float damageAmount = contactDot * Body.Mass / limb.character.Mass;
                limb.character.LastDamageSource = submarine;
                limb.character.DamageLimb(ConvertUnits.ToDisplayUnits(collision.ImpactPos), limb,
                                          AfflictionPrefab.ImpactDamage.Instantiate(damageAmount).ToEnumerable(), 0.0f, true, 0.0f);

                if (limb.character.IsDead)
                {
                    foreach (LimbJoint limbJoint in limb.character.AnimController.LimbJoints)
                    {
                        if (limbJoint.IsSevered || (limbJoint.LimbA != limb && limbJoint.LimbB != limb))
                        {
                            continue;
                        }
                        limb.character.AnimController.SeverLimbJoint(limbJoint);
                    }
                }
            }
        }
Esempio n. 14
0
        /// <summary>
        /// This is a high-level function to cuts fixtures inside the given world, using the start and end points.
        /// Note: We don't support cutting when the start or end is inside a shape.
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="start">The startpoint.</param>
        /// <param name="end">The endpoint.</param>
        /// <param name="thickness">The thickness of the cut</param>
        public static Vector2 Cut(World world, Vector2 start, Vector2 end, float thickness, Category collisionCategories = Category.None)
        {
            // The left side of the cut will remain part of the existing body;
            // the right side will be made into a new body

            List <Fixture> fixtures    = new List <Fixture>();
            List <Vector2> entryPoints = new List <Vector2>();
            List <Vector2> exitPoints  = new List <Vector2>();



            List <RayCastResult> results = new List <RayCastResult>();
            //float blockingFraction = float.MaxValue;
            Vector2 stoppingPoint = end;

            //We don't support cutting when the start or end is inside a shape.
            //if (world.TestPoint(start) != null || world.TestPoint(end) != null)
            //    return;

            //Get the entry points
            world.RayCast((f, p, n, fr) =>
            {
                RayCastResult r = new RayCastResult();
                r.f             = f;
                r.p             = p;
                r.fr            = fr;
                results.Add(r);

                return(1);
            }, start, end);


            results = results.OrderBy(p => p.fr).ToList();

            foreach (RayCastResult r in results)
            {
                if ((r.f.CollisionCategories & collisionCategories) != Category.None)
                {
                    stoppingPoint = r.p;
                    break;
                }
                if (!r.f.TestPoint(ref end))
                {
                    if (world.FixtureCut != null)
                    {
                        world.FixtureCut(r.f);
                    }
                    fixtures.Add(r.f);
                    entryPoints.Add(r.p);
                }
            }


            //Reverse the ray to get the exitpoints
            world.RayCast((f, p, n, fr) =>
            {
                if (fixtures.Contains(f))
                {
                    exitPoints.Add(p);
                }
                return(1);
            }, end, start);

            Debug.Assert(entryPoints.Count == exitPoints.Count && entryPoints.Count == fixtures.Count);

            //Fixture containsEnd = world.TestPoint(end);
            //if (containsEnd != null)
            //{
            //    entryPoints.RemoveAt(0);
            //    fixtures.Remove(containsEnd);
            //}
            //Fixture containsStart = world.TestPoint(start);
            //if (containsStart != null)
            //{
            //    exitPoints.RemoveAt(exitPoints.Count - 1);
            //    fixtures.Remove(containsStart);
            //}

            //We only have a single point. We need at least 2
            if (entryPoints.Count + exitPoints.Count < 2)
            {
                return(stoppingPoint);
            }

            var query =
                (from fix in fixtures
                 select fix.Body).Distinct();

            foreach (Body b in query)
            {
                if (b == null || b.BodyType == BodyType.Static)
                {
                    continue;
                }

                ContactEdge edge = b.ContactList;
                while (edge != null)
                {
                    Contact c = edge.Contact;
                    edge = edge.Next;
                    world.ContactManager.Destroy(c);
                }

                List <Body> leftBodies  = new List <Body>();
                List <Body> rightBodies = new List <Body>();
                //Body rightBody = new Body(world);

                List <Joint> leftJoints  = new List <Joint>();
                List <Joint> rightJoints = new List <Joint>();

                foreach (Joint j in b.JointList)
                {
                    if (isLeft(start, end, j.WorldAnchorA))
                    {
                        leftJoints.Add(j);
                    }
                    else
                    {
                        rightJoints.Add(j);
                    }
                }

                //List<Fixture> leftList = new List<Fixture>();
                //List<Fixture> rightList = new List<Fixture>();
                Fixture[] bodyFixtures = new Fixture[b.FixtureList.Count];
                b.FixtureList.CopyTo(bodyFixtures);
                b.FixtureList.Clear();
                //leftBodies.Add(b);

                // For each fixture that was sliced through...
                foreach (Fixture fix in (from f in bodyFixtures where fixtures.Contains(f) select f))
                {
                    int i = fixtures.IndexOf(fix);

                    // split this in half and put the halves in the over/under lists
                    Vertices first;
                    Vertices second;
                    SplitShape(fix, entryPoints[i], exitPoints[i], thickness, out first, out second);
                    if (!SanityCheck(first) || !SanityCheck(second))
                    {
                        continue;
                    }
                    PolygonShape leftShape  = new PolygonShape(first, fix.Shape.Density);
                    PolygonShape rightShape = new PolygonShape(second, fix.Shape.Density);

                    if (!b.FixtureList.Any())
                    {
                        if (leftShape.MassData.Area > rightShape.MassData.Area)
                        {
                            b.CreateFixture(leftShape, fix.UserData);
                            leftBodies.Add(b);
                            GlomFixture(world, b, rightBodies, rightShape, fix.UserData, rightJoints);
                        }
                        else
                        {
                            b.CreateFixture(rightShape, fix.UserData);
                            rightBodies.Add(b);
                            GlomFixture(world, b, leftBodies, leftShape, fix.UserData, leftJoints);
                        }
                    }
                    else
                    {
                        GlomFixture(world, b, leftBodies, leftShape, fix.UserData, leftJoints);
                        GlomFixture(world, b, rightBodies, rightShape, fix.UserData, rightJoints);
                    }
                }

                // for each fixture that was NOT sliced through...
                foreach (Fixture fix in (from f in bodyFixtures where !fixtures.Contains(f) select f))
                {
                    if (isLeft(start, end, fix))
                    {
                        GlomFixture(world, b, leftBodies, fix.Shape, fix.UserData, leftJoints);
                    }
                    else
                    {
                        GlomFixture(world, b, rightBodies, fix.Shape, fix.UserData, rightJoints);
                        //rightBody.CreateFixture(fix.Shape.Clone(), fix.UserData);
                    }
                }

                foreach (Body bod in leftBodies.Concat(rightBodies))
                {
                    bod.ResetMassData();
                    bod.BodyType        = BodyType.Dynamic;
                    bod.Rotation        = b.Rotation;
                    bod.LinearVelocity  = b.LinearVelocity;
                    bod.AngularVelocity = b.AngularVelocity;
                    bod.Position        = b.Position;
                }

                //b.JointList = null;
                //world.RemoveBody(b);

                foreach (Fixture f in bodyFixtures)
                {
                    b.DestroyFixture(f);
                }
                world.ProcessChanges();
            }

            return(stoppingPoint);
        }
Esempio n. 15
0
        private void SolveTOI(ref TimeStep step)
        {
            Island.Reset(2 * Settings.MaxTOIContacts, Settings.MaxTOIContacts, 0, ContactManager);

            if (_stepComplete)
            {
                for (int i = 0; i < BodyList.Count; i++)
                {
                    BodyList[i]._flags       &= ~BodyFlags.IslandFlag;
                    BodyList[i]._sweep.Alpha0 = 0.0f;
                }

                for (int i = 0; i < ContactManager.ContactList.Count; i++)
                {
                    Contact c = ContactManager.ContactList[i];

                    // Invalidate TOI
                    c._flags   &= ~ContactFlags.IslandFlag;
                    c._flags   &= ~ContactFlags.TOIFlag;
                    c._toiCount = 0;
                    c._toi      = 1.0f;
                }
            }

            // Find TOI events and solve them.
            for (;;)
            {
                // Find the first TOI.
                Contact minContact = null;
                float   minAlpha   = 1.0f;

                for (int i = 0; i < ContactManager.ContactList.Count; i++)
                {
                    Contact c = ContactManager.ContactList[i];

                    // Is this contact disabled?
                    if (c.Enabled == false)
                    {
                        continue;
                    }

                    // Prevent excessive sub-stepping.
                    if (c._toiCount > Settings.MaxSubSteps)
                    {
                        continue;
                    }

                    float alpha;
                    if (c.TOIFlag)
                    {
                        // This contact has a valid cached TOI.
                        alpha = c._toi;
                    }
                    else
                    {
                        Fixture fA = c.FixtureA;
                        Fixture fB = c.FixtureB;

                        // Is there a sensor?
                        if (fA.IsSensor || fB.IsSensor)
                        {
                            continue;
                        }

                        Body bA = fA.Body;
                        Body bB = fB.Body;

                        BodyType typeA = bA.BodyType;
                        BodyType typeB = bB.BodyType;
                        Debug.Assert(typeA == BodyType.Dynamic || typeB == BodyType.Dynamic);

                        bool activeA = bA.Awake && typeA != BodyType.Static;
                        bool activeB = bB.Awake && typeB != BodyType.Static;

                        // Is at least one body active (awake and dynamic or kinematic)?
                        if (activeA == false && activeB == false)
                        {
                            continue;
                        }

                        bool collideA = (bA.IsBullet || typeA != BodyType.Dynamic) && (fA.IgnoreCCDWith & fB.CollisionCategories) == 0 && !bA.IgnoreCCD;
                        bool collideB = (bB.IsBullet || typeB != BodyType.Dynamic) && (fB.IgnoreCCDWith & fA.CollisionCategories) == 0 && !bB.IgnoreCCD;

                        // Are these two non-bullet dynamic bodies?
                        if (collideA == false && collideB == false)
                        {
                            continue;
                        }

                        // Compute the TOI for this contact.
                        // Put the sweeps onto the same time interval.
                        float alpha0 = bA._sweep.Alpha0;

                        if (bA._sweep.Alpha0 < bB._sweep.Alpha0)
                        {
                            alpha0 = bB._sweep.Alpha0;
                            bA._sweep.Advance(alpha0);
                        }
                        else if (bB._sweep.Alpha0 < bA._sweep.Alpha0)
                        {
                            alpha0 = bA._sweep.Alpha0;
                            bB._sweep.Advance(alpha0);
                        }

                        Debug.Assert(alpha0 < 1.0f);

                        // Compute the time of impact in interval [0, minTOI]
                        TOIInput input = new TOIInput();
                        input.ProxyA = new DistanceProxy(fA.Shape, c.ChildIndexA);
                        input.ProxyB = new DistanceProxy(fB.Shape, c.ChildIndexB);
                        input.SweepA = bA._sweep;
                        input.SweepB = bB._sweep;
                        input.TMax   = 1.0f;

                        TOIOutput output;
                        TimeOfImpact.CalculateTimeOfImpact(ref input, out output);

                        // Beta is the fraction of the remaining portion of the .
                        float beta = output.T;
                        if (output.State == TOIOutputState.Touching)
                        {
                            alpha = Math.Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
                        }
                        else
                        {
                            alpha = 1.0f;
                        }

                        c._toi    = alpha;
                        c._flags &= ~ContactFlags.TOIFlag;
                    }

                    if (alpha < minAlpha)
                    {
                        // This is the minimum TOI found so far.
                        minContact = c;
                        minAlpha   = alpha;
                    }
                }

                if (minContact == null || 1.0f - 10.0f * Settings.Epsilon < minAlpha)
                {
                    // No more TOI events. Done!
                    _stepComplete = true;
                    break;
                }

                // Advance the bodies to the TOI.
                Fixture fA1 = minContact.FixtureA;
                Fixture fB1 = minContact.FixtureB;
                Body    bA0 = fA1.Body;
                Body    bB0 = fB1.Body;

                Sweep backup1 = bA0._sweep;
                Sweep backup2 = bB0._sweep;

                bA0.Advance(minAlpha);
                bB0.Advance(minAlpha);

                // The TOI contact likely has some new contact points.
                minContact.Update(ContactManager);
                minContact._flags &= ~ContactFlags.TOIFlag;
                ++minContact._toiCount;

                // Is the contact solid?
                if (minContact.Enabled == false || minContact.IsTouching == false)
                {
                    // Restore the sweeps.
                    minContact._flags &= ~ContactFlags.EnabledFlag;
                    bA0._sweep         = backup1;
                    bB0._sweep         = backup2;
                    bA0.SynchronizeTransform();
                    bB0.SynchronizeTransform();
                    continue;
                }

                bA0.Awake = true;
                bB0.Awake = true;

                // Build the island
                Island.Clear();
                Island.Add(bA0);
                Island.Add(bB0);
                Island.Add(minContact);

                bA0._flags        |= BodyFlags.IslandFlag;
                bB0._flags        |= BodyFlags.IslandFlag;
                minContact._flags &= ~ContactFlags.IslandFlag;

                // Get contacts on bodyA and bodyB.
                Body[] bodies = { bA0, bB0 };
                for (int i = 0; i < 2; ++i)
                {
                    Body body = bodies[i];
                    if (body.BodyType == BodyType.Dynamic)
                    {
                        for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)
                        {
                            Contact contact = ce.Contact;

                            if (Island.BodyCount == Island.BodyCapacity)
                            {
                                break;
                            }

                            if (Island.ContactCount == Island.ContactCapacity)
                            {
                                break;
                            }

                            // Has this contact already been added to the island?
                            if (contact.IslandFlag)
                            {
                                continue;
                            }

                            // Only add static, kinematic, or bullet bodies.
                            Body other = ce.Other;
                            if (other.BodyType == BodyType.Dynamic &&
                                body.IsBullet == false && other.IsBullet == false)
                            {
                                continue;
                            }

                            // Skip sensors.
                            if (contact.FixtureA.IsSensor || contact.FixtureB.IsSensor)
                            {
                                continue;
                            }

                            // Tentatively advance the body to the TOI.
                            Sweep backup = other._sweep;
                            if (!other.IsIsland)
                            {
                                other.Advance(minAlpha);
                            }

                            // Update the contact points
                            contact.Update(ContactManager);

                            // Was the contact disabled by the user?
                            if (contact.Enabled == false)
                            {
                                other._sweep = backup;
                                other.SynchronizeTransform();
                                continue;
                            }

                            // Are there contact points?
                            if (contact.IsTouching == false)
                            {
                                other._sweep = backup;
                                other.SynchronizeTransform();
                                continue;
                            }

                            // Add the contact to the island
                            minContact._flags |= ContactFlags.IslandFlag;
                            Island.Add(contact);

                            // Has the other body already been added to the island?
                            if (other.IsIsland)
                            {
                                continue;
                            }

                            // Add the other body to the island.
                            other._flags |= BodyFlags.IslandFlag;

                            if (other.BodyType != BodyType.Static)
                            {
                                other.Awake = true;
                            }

                            Island.Add(other);
                        }
                    }
                }

                TimeStep subStep;
                subStep.dt      = (1.0f - minAlpha) * step.dt;
                subStep.inv_dt  = 1.0f / subStep.dt;
                subStep.dtRatio = 1.0f;
                Island.SolveTOI(ref subStep, bA0.IslandIndex, bB0.IslandIndex);

                // Reset island flags and synchronize broad-phase proxies.
                for (int i = 0; i < Island.BodyCount; ++i)
                {
                    Body body = Island.Bodies[i];
                    body._flags &= ~BodyFlags.IslandFlag;

                    if (body.BodyType != BodyType.Dynamic)
                    {
                        continue;
                    }

                    body.SynchronizeFixtures();

                    // Invalidate all contact TOIs on this displaced body.
                    for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)
                    {
                        ce.Contact._flags &= ~ContactFlags.TOIFlag;
                        ce.Contact._flags &= ~ContactFlags.IslandFlag;
                    }
                }

                // Commit fixture proxy movements to the broad-phase so that new contacts are created.
                // Also, some contacts can be destroyed.
                ContactManager.FindNewContacts();

                if (Settings.EnableSubStepping)
                {
                    _stepComplete = false;
                    break;
                }
            }
        }
Esempio n. 16
0
        private void ProcessAddedJoints()
        {
            if (_jointAddList.Count > 0)
            {
                foreach (Joint joint in _jointAddList)
                {
                    // Connect to the world list.
                    JointList.Add(joint);

                    // Connect to the bodies' doubly linked lists.
                    joint.EdgeA.Joint = joint;
                    joint.EdgeA.Other = joint.BodyB;
                    joint.EdgeA.Prev  = null;
                    joint.EdgeA.Next  = joint.BodyA.JointList;

                    if (joint.BodyA.JointList != null)
                    {
                        joint.BodyA.JointList.Prev = joint.EdgeA;
                    }

                    joint.BodyA.JointList = joint.EdgeA;

                    // WIP David
                    if (!joint.IsFixedType())
                    {
                        joint.EdgeB.Joint = joint;
                        joint.EdgeB.Other = joint.BodyA;
                        joint.EdgeB.Prev  = null;
                        joint.EdgeB.Next  = joint.BodyB.JointList;

                        if (joint.BodyB.JointList != null)
                        {
                            joint.BodyB.JointList.Prev = joint.EdgeB;
                        }

                        joint.BodyB.JointList = joint.EdgeB;

                        Body bodyA = joint.BodyA;
                        Body bodyB = joint.BodyB;

                        // If the joint prevents collisions, then flag any contacts for filtering.
                        if (joint.CollideConnected == false)
                        {
                            ContactEdge edge = bodyB.ContactList;
                            while (edge != null)
                            {
                                if (edge.Other == bodyA)
                                {
                                    // Flag the contact for filtering at the next time step (where either
                                    // body is awake).
                                    edge.Contact._flags |= ContactFlags.FilterFlag;
                                }

                                edge = edge.Next;
                            }
                        }
                    }

                    JointAdded?.Invoke(joint);

                    // Note: creating a joint doesn't wake the bodies.
                }

                _jointAddList.Clear();
            }
        }
Esempio n. 17
0
        private void AddPair(object proxyUserDataA, object proxyUserDataB)
        {
            var proxyA = (FixtureProxy)proxyUserDataA;
            var proxyB = (FixtureProxy)proxyUserDataB;

            Fixture fixtureA = proxyA.fixture;
            Fixture fixtureB = proxyB.fixture;

            int indexA = proxyA.childIndex;
            int indexB = proxyB.childIndex;

            Body bodyA = fixtureA.Body;
            Body bodyB = fixtureB.Body;

            // Are the fixtures on the same body?
            if (bodyA == bodyB)
            {
                return;
            }

            // TODO_ERIN use a hash table to remove a potential bottleneck when both
            // bodies have a lot of contacts.
            // Does a contact already exist?
            ContactEdge edge = bodyB.GetContactList();

            while (edge != null)
            {
                if (edge.other == bodyA)
                {
                    Fixture fA = edge.contact.GetFixtureA();
                    Fixture fB = edge.contact.GetFixtureB();
                    int     iA = edge.contact.GetChildIndexA();
                    int     iB = edge.contact.GetChildIndexB();

                    if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
                    // A contact already exists.
                    {
                        return;
                    }

                    if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
                    // A contact already exists.
                    {
                        return;
                    }
                }

                edge = edge.next;
            }

            // Does a joint override collision? Is at least one body dynamic?
            if (bodyB.ShouldCollide(bodyA) == false)
            {
                return;
            }

            // Check user filtering.
            if (m_contactFilter != null && m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false)
            {
                return;
            }

            // Call the factory.
            var c = Contact.Create(fixtureA, indexA, fixtureB, indexB);

            if (c == null)
            {
                return;
            }

            // Contact creation may swap fixtures.
            fixtureA = c.GetFixtureA();
            fixtureB = c.GetFixtureB();
            indexA   = c.GetChildIndexA();
            indexB   = c.GetChildIndexB();
            bodyA    = fixtureA.GetBody();
            bodyB    = fixtureB.GetBody();

            // Insert into the world.
            c.m_prev = null;
            c.m_next = m_contactList;
            if (m_contactList != null)
            {
                m_contactList.m_prev = c;
            }

            m_contactList = c;

            // Connect to island graph.

            // Connect to body A
            c.m_nodeA.contact = c;
            c.m_nodeA.other   = bodyB;

            c.m_nodeA.prev = null;
            c.m_nodeA.next = bodyA.m_contactList;
            if (bodyA.m_contactList != null)
            {
                bodyA.m_contactList.prev = c.m_nodeA;
            }

            bodyA.m_contactList = c.m_nodeA;

            // Connect to body B
            c.m_nodeB.contact = c;
            c.m_nodeB.other   = bodyA;

            c.m_nodeB.prev = null;
            c.m_nodeB.next = bodyB.m_contactList;
            if (bodyB.m_contactList != null)
            {
                bodyB.m_contactList.prev = c.m_nodeB;
            }

            bodyB.m_contactList = c.m_nodeB;

            ++m_contactCount;
        }
Esempio n. 18
0
        /// <summary>
        /// Create a joint to constrain bodies together. This may cause the connected bodies to cease colliding.
        /// Warning: This function is locked during callbacks.
        /// </summary>
        /// <param name="joint">The joint.</param>
        public void AddJoint(Joint joint)
        {
            Debug.Assert(!IsLocked);
            if (IsLocked)
            {
                return;
            }

            // Connect to the world list.
            JointList.Add(joint);

            // Connect to the bodies' doubly linked lists.
            joint.EdgeA.Joint = joint;
            joint.EdgeA.Other = joint.BodyB;
            joint.EdgeA.Prev  = null;
            joint.EdgeA.Next  = joint.BodyA.JointList;

            if (joint.BodyA.JointList != null)
            {
                joint.BodyA.JointList.Prev = joint.EdgeA;
            }

            joint.BodyA.JointList = joint.EdgeA;

            // WIP David
            if (!joint.IsFixedType())
            {
                joint.EdgeB.Joint = joint;
                joint.EdgeB.Other = joint.BodyA;
                joint.EdgeB.Prev  = null;
                joint.EdgeB.Next  = joint.BodyB.JointList;

                if (joint.BodyB.JointList != null)
                {
                    joint.BodyB.JointList.Prev = joint.EdgeB;
                }

                joint.BodyB.JointList = joint.EdgeB;
            }

            // WIP David
            if (!joint.IsFixedType())
            {
                Body bodyA = joint.BodyA;
                Body bodyB = joint.BodyB;

                // If the joint prevents collisions, then flag any contacts for filtering.
                if (joint.CollideConnected == false)
                {
                    ContactEdge edge = bodyB.ContactList;
                    while (edge != null)
                    {
                        if (edge.Other == bodyA)
                        {
                            // Flag the contact for filtering at the next time step (where either
                            // body is awake).
                            edge.Contact.FlagForFiltering();
                        }

                        edge = edge.Next;
                    }
                }
            }

            if (JointAdded != null)
            {
                JointAdded(joint);
            }

            // Note: creating a joint doesn't wake the bodies.
        }
Esempio n. 19
0
        public void UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget)
        {
            float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));

            AttackTimer += deltaTime;

            body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque);

            bool wasHit = false;

            if (damageTarget != null)
            {
                switch (attack.HitDetectionType)
                {
                case HitDetection.Distance:
                    wasHit = dist < attack.DamageRange;
                    break;

                case HitDetection.Contact:
                    List <Body> targetBodies = new List <Body>();
                    if (damageTarget is Character)
                    {
                        Character targetCharacter = (Character)damageTarget;
                        foreach (Limb limb in targetCharacter.AnimController.Limbs)
                        {
                            if (!limb.IsSevered && limb.body?.FarseerBody != null)
                            {
                                targetBodies.Add(limb.body.FarseerBody);
                            }
                        }
                    }
                    else if (damageTarget is Structure)
                    {
                        Structure targetStructure = (Structure)damageTarget;

                        if (character.Submarine == null && targetStructure.Submarine != null)
                        {
                            targetBodies.Add(targetStructure.Submarine.PhysicsBody.FarseerBody);
                        }
                        else
                        {
                            targetBodies.AddRange(targetStructure.Bodies);
                        }
                    }
                    else if (damageTarget is Item)
                    {
                        Item targetItem = damageTarget as Item;
                        if (targetItem.body?.FarseerBody != null)
                        {
                            targetBodies.Add(targetItem.body.FarseerBody);
                        }
                    }

                    if (targetBodies != null)
                    {
                        ContactEdge contactEdge = body.FarseerBody.ContactList;
                        while (contactEdge != null)
                        {
                            if (contactEdge.Contact != null &&
                                contactEdge.Contact.IsTouching &&
                                targetBodies.Any(b => b == contactEdge.Contact.FixtureA?.Body || b == contactEdge.Contact.FixtureB?.Body))
                            {
                                wasHit = true;
                                break;
                            }

                            contactEdge = contactEdge.Next;
                        }
                    }
                    break;
                }
            }

            if (wasHit)
            {
                if (AttackTimer >= attack.Duration && damageTarget != null)
                {
                    attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
                    SoundTimer = SoundInterval;
                }
            }

            Vector2 diff = attackPosition - SimPosition;

            if (diff.LengthSquared() < 0.00001f)
            {
                return;
            }

            if (attack.ApplyForceOnLimbs != null)
            {
                foreach (int limbIndex in attack.ApplyForceOnLimbs)
                {
                    if (limbIndex < 0 || limbIndex >= character.AnimController.Limbs.Length)
                    {
                        continue;
                    }

                    Limb    limb     = character.AnimController.Limbs[limbIndex];
                    Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
                    limb.body.ApplyLinearImpulse(
                        limb.Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
                }
            }
            else
            {
                Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
                body.ApplyLinearImpulse(Mass * attack.Force *
                                        Vector2.Normalize(attackPosition - SimPosition), forcePos);
            }
        }
Esempio n. 20
0
        private void ProcessRemovedJoints()
        {
            if (_jointRemoveList.Count > 0)
            {
                foreach (Joint joint in _jointRemoveList)
                {
                    bool collideConnected = joint.CollideConnected;

                    // Remove from the world list.
                    JointList.Remove(joint);

                    // Disconnect from island graph.
                    Body bodyA = joint.BodyA;
                    Body bodyB = joint.BodyB;

                    // Wake up connected bodies.
                    bodyA.Awake = true;

                    // WIP David
                    if (!joint.IsFixedType())
                    {
                        bodyB.Awake = true;
                    }

                    // Remove from body 1.
                    if (joint.EdgeA.Prev != null)
                    {
                        joint.EdgeA.Prev.Next = joint.EdgeA.Next;
                    }

                    if (joint.EdgeA.Next != null)
                    {
                        joint.EdgeA.Next.Prev = joint.EdgeA.Prev;
                    }

                    if (joint.EdgeA == bodyA.JointList)
                    {
                        bodyA.JointList = joint.EdgeA.Next;
                    }

                    joint.EdgeA.Prev = null;
                    joint.EdgeA.Next = null;

                    // WIP David
                    if (!joint.IsFixedType())
                    {
                        // Remove from body 2
                        if (joint.EdgeB.Prev != null)
                        {
                            joint.EdgeB.Prev.Next = joint.EdgeB.Next;
                        }

                        if (joint.EdgeB.Next != null)
                        {
                            joint.EdgeB.Next.Prev = joint.EdgeB.Prev;
                        }

                        if (joint.EdgeB == bodyB.JointList)
                        {
                            bodyB.JointList = joint.EdgeB.Next;
                        }

                        joint.EdgeB.Prev = null;
                        joint.EdgeB.Next = null;

                        // If the joint prevents collisions, then flag any contacts for filtering.
                        if (collideConnected == false)
                        {
                            ContactEdge edge = bodyB.ContactList;
                            while (edge != null)
                            {
                                if (edge.Other == bodyA)
                                {
                                    // Flag the contact for filtering at the next time step (where either
                                    // body is awake).
                                    edge.Contact._flags |= ContactFlags.FilterFlag;
                                }

                                edge = edge.Next;
                            }
                        }
                    }

                    JointRemoved?.Invoke(joint);
                }

                _jointRemoveList.Clear();
            }
        }
Esempio n. 21
0
        /// <summary>
        // Advance a dynamic body to its first time of contact
        // and adjust the position to ensure clearance.
        /// </summary>
        /// <param name="body">The body.</param>
        private void SolveTOI(Body body)
        {
            // Find the minimum contact.
            Contact toiContact = null;
            float   toi        = 1.0f;
            Body    toiOther   = null;
            bool    found;
            int     count;
            int     iter = 0;

            bool bullet = body.IsBullet;

            // Iterate until all contacts agree on the minimum TOI. We have
            // to iterate because the TOI algorithm may skip some intermediate
            // collisions when objects rotate through each other.
            do
            {
                count = 0;
                found = false;
                for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)
                {
                    if (ce.Contact == toiContact)
                    {
                        continue;
                    }

                    Body     other = ce.Other;
                    BodyType type  = other.BodyType;

                    // Only bullets perform TOI with dynamic bodies.
                    if (bullet)
                    {
                        // Bullets only perform TOI with bodies that have their TOI resolved.
                        if ((other.Flags & BodyFlags.Toi) == 0)
                        {
                            continue;
                        }

                        // No repeated hits on non-static bodies
                        if (type != BodyType.Static && (ce.Contact.Flags & ContactFlags.BulletHit) != 0)
                        {
                            continue;
                        }
                    }
                    else if (type == BodyType.Dynamic)
                    {
                        continue;
                    }

                    // Check for a disabled contact.
                    Contact contact = ce.Contact;
                    if (contact.Enabled == false)
                    {
                        continue;
                    }

                    // Prevent infinite looping.
                    if (contact.TOICount > 10)
                    {
                        continue;
                    }

                    Fixture fixtureA = contact.FixtureA;
                    Fixture fixtureB = contact.FixtureB;
                    int     indexA   = contact.ChildIndexA;
                    int     indexB   = contact.ChildIndexB;

                    // Cull sensors.
                    if (fixtureA.IsSensor || fixtureB.IsSensor)
                    {
                        continue;
                    }

                    Body bodyA = fixtureA.Body;
                    Body bodyB = fixtureB.Body;

                    // Compute the time of impact in interval [0, minTOI]
                    TOIInput input = new TOIInput();
                    input.ProxyA.Set(fixtureA.Shape, indexA);
                    input.ProxyB.Set(fixtureB.Shape, indexB);
                    input.SweepA = bodyA.Sweep;
                    input.SweepB = bodyB.Sweep;
                    input.TMax   = toi;

                    TOIOutput output;
                    TimeOfImpact.CalculateTimeOfImpact(out output, ref input);

                    if (output.State == TOIOutputState.Touching && output.T < toi)
                    {
                        toiContact = contact;
                        toi        = output.T;
                        toiOther   = other;
                        found      = true;
                    }

                    ++count;
                }

                ++iter;
            } while (found && count > 1 && iter < 50);

            if (toiContact == null)
            {
                body.Advance(1.0f);
                return;
            }

            Sweep backup = body.Sweep;

            body.Advance(toi);
            toiContact.Update(ContactManager);
            if (toiContact.Enabled == false)
            {
                // Contact disabled. Backup and recurse.
                body.Sweep = backup;
                SolveTOI(body);
            }

            ++toiContact.TOICount;

            // Update all the valid contacts on this body and build a contact island.
            count = 0;
            for (ContactEdge ce = body.ContactList; (ce != null) && (count < Settings.MaxTOIContacts); ce = ce.Next)
            {
                Body     other = ce.Other;
                BodyType type  = other.BodyType;

                // Only perform correction with static bodies, so the
                // body won't get pushed out of the world.
                if (type == BodyType.Dynamic)
                {
                    continue;
                }

                // Check for a disabled contact.
                Contact contact = ce.Contact;
                if (contact.Enabled == false)
                {
                    continue;
                }

                Fixture fixtureA = contact.FixtureA;
                Fixture fixtureB = contact.FixtureB;

                // Cull sensors.
                if (fixtureA.IsSensor || fixtureB.IsSensor)
                {
                    continue;
                }

                // The contact likely has some new contact points. The listener
                // gives the user a chance to disable the contact.
                if (contact != toiContact)
                {
                    contact.Update(ContactManager);
                }

                // Did the user disable the contact?
                if (contact.Enabled == false)
                {
                    // Skip this contact.
                    continue;
                }

                if (contact.IsTouching() == false)
                {
                    continue;
                }

                _toiContacts[count] = contact;
                ++count;
            }

            // Reduce the TOI body's overlap with the contact island.
            _toiSolver.Initialize(_toiContacts, count, body);

            const float k_toiBaumgarte = 0.75f;

            // bool solved = false;
            for (int i = 0; i < 20; ++i)
            {
                bool contactsOkay = _toiSolver.Solve(k_toiBaumgarte);
                if (contactsOkay)
                {
                    // solved = true;
                    break;
                }
            }

            if (toiOther.BodyType != BodyType.Static)
            {
                toiContact.Flags |= ContactFlags.BulletHit;
            }
        }
Esempio n. 22
0
        private void Solve(ref TimeStep step)
        {
            // Size the island for the worst case.
            Island.Reset(BodyList.Count,
                         ContactManager.ContactList.Count,
                         JointList.Count,
                         ContactManager);

            // Clear all the island flags.
            foreach (Body b in BodyList)
            {
                b._flags &= ~BodyFlags.IslandFlag;
            }

            foreach (Contact c in ContactManager.ContactList)
            {
                c._flags &= ~ContactFlags.IslandFlag;
            }

            foreach (Joint j in JointList)
            {
                j.IslandFlag = false;
            }

            // Build and simulate all awake islands.
            int stackSize = BodyList.Count;

            if (stackSize > _stack.Length)
            {
                _stack = new Body[Math.Max(_stack.Length * 2, stackSize)];
            }

            for (int index = BodyList.Count - 1; index >= 0; index--)
            {
                Body seed = BodyList[index];
                if ((seed._flags & BodyFlags.IslandFlag) == BodyFlags.IslandFlag)
                {
                    continue;
                }

                if (seed.Awake == false || seed.Enabled == false)
                {
                    continue;
                }

                // The seed can be dynamic or kinematic.
                if (seed.BodyType == BodyType.Static)
                {
                    continue;
                }

                // Reset island and stack.
                Island.Clear();
                int stackCount = 0;
                _stack[stackCount++] = seed;

                seed._flags |= BodyFlags.IslandFlag;

                // Perform a depth first search (DFS) on the constraint graph.
                while (stackCount > 0)
                {
                    // Grab the next body off the stack and add it to the island.
                    Body b = _stack[--stackCount];
                    Debug.Assert(b.Enabled);
                    Island.Add(b);

                    // Make sure the body is awake (without resetting sleep timer).
                    b._flags |= BodyFlags.AwakeFlag;

                    // To keep islands as small as possible, we don't
                    // propagate islands across static bodies.
                    if (b.BodyType == BodyType.Static)
                    {
                        continue;
                    }

                    // Search all contacts connected to this body.
                    for (ContactEdge ce = b.ContactList; ce != null; ce = ce.Next)
                    {
                        Contact contact = ce.Contact;

                        // Has this contact already been added to an island?
                        if (contact.IslandFlag)
                        {
                            continue;
                        }

                        // Is this contact solid and touching?
                        if (ce.Contact.Enabled == false || ce.Contact.IsTouching == false)
                        {
                            continue;
                        }

                        // Skip sensors.
                        bool sensorA = contact.FixtureA.IsSensor;
                        bool sensorB = contact.FixtureB.IsSensor;
                        if (sensorA || sensorB)
                        {
                            continue;
                        }

                        Island.Add(contact);
                        contact._flags |= ContactFlags.IslandFlag;

                        Body other = ce.Other;

                        // Was the other body already added to this island?
                        if (other.IsIsland)
                        {
                            continue;
                        }

                        Debug.Assert(stackCount < stackSize);
                        _stack[stackCount++] = other;

                        other._flags |= BodyFlags.IslandFlag;
                    }

                    // Search all joints connect to this body.
                    for (JointEdge je = b.JointList; je != null; je = je.Next)
                    {
                        if (je.Joint.IslandFlag)
                        {
                            continue;
                        }

                        Body other = je.Other;

                        // WIP David
                        //Enter here when it's a non-fixed joint. Non-fixed joints have a other body.
                        if (other != null)
                        {
                            // Don't simulate joints connected to inactive bodies.
                            if (other.Enabled == false)
                            {
                                continue;
                            }

                            Island.Add(je.Joint);
                            je.Joint.IslandFlag = true;

                            if (other.IsIsland)
                            {
                                continue;
                            }

                            Debug.Assert(stackCount < stackSize);
                            _stack[stackCount++] = other;

                            other._flags |= BodyFlags.IslandFlag;
                        }
                        else
                        {
                            Island.Add(je.Joint);
                            je.Joint.IslandFlag = true;
                        }
                    }
                }

                Island.Solve(ref step, ref Gravity);

                // Post solve cleanup.
                for (int i = 0; i < Island.BodyCount; ++i)
                {
                    // Allow static bodies to participate in other islands.
                    Body b = Island.Bodies[i];
                    if (b.BodyType == BodyType.Static)
                    {
                        b._flags &= ~BodyFlags.IslandFlag;
                    }
                }
            }

            // Synchronize fixtures, check for out of range bodies.

            foreach (Body b in BodyList)
            {
                // If a body was not in an island then it did not move.
                if (!b.IsIsland)
                {
                    continue;
                }

                if (b.BodyType == BodyType.Static)
                {
                    continue;
                }

                // Update fixtures (for broad-phase).
                b.SynchronizeFixtures();
            }

            // Look for new contacts.
            ContactManager.FindNewContacts();
        }
Esempio n. 23
0
        internal XForm _xf; // the body origin transform

        #endregion Fields

        #region Constructors

        internal Body(BodyDef bd, World world)
        {
            _flags = 0;

            if (bd.isBullet)
            {
                _flags |= BodyFlags.Bullet;
            }
            if (bd.fixedRotation)
            {
                _flags |= BodyFlags.FixedRotation;
            }
            if (bd.allowSleep)
            {
                _flags |= BodyFlags.AllowSleep;
            }
            if (bd.isSleeping)
            {
                _flags |= BodyFlags.Sleep;
            }

            _world = world;

            _xf.Position = bd.position;
            _xf.R.Set(bd.angle);

            _sweep.localCenter = bd.massData.center;
            _sweep.t0 = 1.0f;
            _sweep.a0 = _sweep.a = bd.angle;
            _sweep.c0 = _sweep.c = MathUtils.Multiply(ref _xf, _sweep.localCenter);

            _jointList = null;
            _contactList = null;
            _prev = null;
            _next = null;

            _linearVelocity = bd.linearVelocity;
            _angularVelocity = bd.angularVelocity;

            _linearDamping = bd.linearDamping;
            _angularDamping = bd.angularDamping;

            _force = new Vector2(0.0f, 0.0f);
            _torque = 0.0f;

            _linearVelocity = Vector2.Zero;
            _angularVelocity = 0.0f;

            _sleepTime = 0.0f;

            _invMass = 0.0f;
            _I = 0.0f;
            _invI = 0.0f;

            _mass = bd.massData.mass;

            if (_mass > 0.0f)
            {
                _invMass = 1.0f / _mass;
            }

            _I = bd.massData.i;

            if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
            {
                _invI = 1.0f / _I;
            }

            if (_invMass == 0.0f && _invI == 0.0f)
            {
                _type = BodyType.Static;
            }
            else
            {
                _type = BodyType.Dynamic;
            }

            _userData = bd.userData;

            _fixtureList = null;
            _fixtureCount = 0;
        }
        // Broad-phase callback.
        private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB)
        {
            Fixture fixtureA = proxyA.Fixture;
            Fixture fixtureB = proxyB.Fixture;

            int indexA = proxyA.ChildIndex;
            int indexB = proxyB.ChildIndex;

            Body bodyA = fixtureA.Body;
            Body bodyB = fixtureB.Body;

            // Are the fixtures on the same body?
            if (bodyA == bodyB)
            {
                return;
            }

            // Does a contact already exist?
            ContactEdge edge = bodyB.ContactList;

            while (edge != null)
            {
                if (edge.Other == bodyA)
                {
                    Fixture fA = edge.Contact.FixtureA;
                    Fixture fB = edge.Contact.FixtureB;
                    int     iA = edge.Contact.ChildIndexA;
                    int     iB = edge.Contact.ChildIndexB;

                    if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
                    {
                        // A contact already exists.
                        return;
                    }

                    if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
                    {
                        // A contact already exists.
                        return;
                    }
                }

                edge = edge.Next;
            }

            // Does a joint override collision? Is at least one body dynamic?
            if (bodyB.ShouldCollide(bodyA) == false)
            {
                return;
            }

            // Check user filtering.
            if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
            {
                return;
            }

            // Call the factory.
            Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);

            // Contact creation may swap fixtures.
            fixtureA = c.FixtureA;
            fixtureB = c.FixtureB;
            indexA   = c.ChildIndexA;
            indexB   = c.ChildIndexB;
            bodyA    = fixtureA.Body;
            bodyB    = fixtureB.Body;

            // Insert into the world.
            c.Prev = null;
            c.Next = ContactList;
            if (ContactList != null)
            {
                ContactList.Prev = c;
            }
            ContactList = c;

            // Connect to island graph.

            // Connect to body A
            c.NodeA.Contact = c;
            c.NodeA.Other   = bodyB;

            c.NodeA.Prev = null;
            c.NodeA.Next = bodyA.ContactList;
            if (bodyA.ContactList != null)
            {
                bodyA.ContactList.Prev = c.NodeA;
            }
            bodyA.ContactList = c.NodeA;

            // Connect to body B
            c.NodeB.Contact = c;
            c.NodeB.Other   = bodyA;

            c.NodeB.Prev = null;
            c.NodeB.Next = bodyB.ContactList;
            if (bodyB.ContactList != null)
            {
                bodyB.ContactList.Prev = c.NodeB;
            }
            bodyB.ContactList = c.NodeB;

            ++ContactCount;
        }
Esempio n. 25
0
        /// <summary>
        /// Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts
        /// associated with this fixture. This will automatically adjust the mass of the body if the body
        /// is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly
        /// destroyed when the body is destroyed.
        /// </summary>
        /// <param name="fixture">the fixture to be removed.</param>
        /// <warning>This function is locked during callbacks.</warning>
        public void DestroyFixture(Fixture fixture)
        {
            Debug.Assert(World.Locked == false);
            if (World.Locked == true)
            {
                return;
            }

            Debug.Assert(fixture.Body == this);

            // Remove the fixture from this body's singly linked list.
            Debug.Assert(FixtureCount > 0);
            Fixture node  = FixtureList;
            Fixture last  = null; // java change
            bool    found = false;

            while (node != null)
            {
                if (node == fixture)
                {
                    node  = fixture.Next;
                    found = true;
                    break;
                }
                last = node;
                node = node.Next;
            }

            // You tried to remove a shape that is not attached to this body.
            Debug.Assert(found);

            // java change, remove it from the list
            if (last == null)
            {
                FixtureList = fixture.Next;
            }
            else
            {
                last.Next = fixture.Next;
            }

            // Destroy any contacts associated with the fixture.
            ContactEdge edge = ContactList;

            while (edge != null)
            {
                Contact c = edge.Contact;
                edge = edge.Next;

                Fixture fixtureA = c.FixtureA;
                Fixture fixtureB = c.FixtureB;

                if (fixture == fixtureA || fixture == fixtureB)
                {
                    // This destroys the contact and removes it from
                    // this body's contact list.
                    World.ContactManager.Destroy(c);
                }
            }

            if ((Flags & TypeFlags.Active) == TypeFlags.Active)
            {
                BroadPhase broadPhase = World.ContactManager.BroadPhase;
                fixture.DestroyProxies(broadPhase);
            }

            fixture.Destroy();
            fixture.Body = null;
            fixture.Next = null;

            --FixtureCount;

            // Reset the mass data.
            ResetMassData();
        }
Esempio n. 26
0
        // Broad-phase callback.
        private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB)
        {
            Fixture fixtureA = proxyA.Fixture;
            Fixture fixtureB = proxyB.Fixture;

            int indexA = proxyA.ChildIndex;
            int indexB = proxyB.ChildIndex;

            Body bodyA = fixtureA.Body;
            Body bodyB = fixtureB.Body;

            // Are the fixtures on the same body?
            if (bodyA == bodyB)
            {
                return;
            }

            // Does a contact already exist?
            ContactEdge edge = bodyB.ContactList;

            while (edge != null)
            {
                if (edge.Other == bodyA)
                {
                    Fixture fA = edge.Contact.FixtureA;
                    Fixture fB = edge.Contact.FixtureB;
                    int     iA = edge.Contact.ChildIndexA;
                    int     iB = edge.Contact.ChildIndexB;

                    if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
                    {
                        // A contact already exists.
                        return;
                    }

                    if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
                    {
                        // A contact already exists.
                        return;
                    }
                }

                edge = edge.Next;
            }

            // Does a joint override collision? Is at least one body dynamic?
            if (bodyB.ShouldCollide(bodyA) == false)
            {
                return;
            }

            //Check default filter
            if (ShouldCollide(fixtureA, fixtureB) == false)
            {
                return;
            }

            // Check user filtering.
            if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
            {
                return;
            }

            //FPE feature: BeforeCollision delegate
            if (fixtureA.BeforeCollision != null && fixtureA.BeforeCollision(fixtureA, fixtureB) == false)
            {
                return;
            }

            if (fixtureB.BeforeCollision != null && fixtureB.BeforeCollision(fixtureB, fixtureA) == false)
            {
                return;
            }

            // Call the factory.
            Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);

            if (c == null)
            {
                return;
            }

            // Contact creation may swap fixtures.
            fixtureA = c.FixtureA;
            fixtureB = c.FixtureB;
            bodyA    = fixtureA.Body;
            bodyB    = fixtureB.Body;

            // Insert into the world.
            ContactList.Add(c);

#if USE_ACTIVE_CONTACT_SET
            ActiveContacts.Add(c);
#endif
            // Connect to island graph.

            // Connect to body A
            c._nodeA.Contact = c;
            c._nodeA.Other   = bodyB;

            c._nodeA.Prev = null;
            c._nodeA.Next = bodyA.ContactList;
            if (bodyA.ContactList != null)
            {
                bodyA.ContactList.Prev = c._nodeA;
            }
            bodyA.ContactList = c._nodeA;

            // Connect to body B
            c._nodeB.Contact = c;
            c._nodeB.Other   = bodyA;

            c._nodeB.Prev = null;
            c._nodeB.Next = bodyB.ContactList;
            if (bodyB.ContactList != null)
            {
                bodyB.ContactList.Prev = c._nodeB;
            }
            bodyB.ContactList = c._nodeB;

            // Wake up the bodies
            if (fixtureA.IsSensor == false && fixtureB.IsSensor == false)
            {
                bodyA.Awake = true;
                bodyB.Awake = true;
            }
        }
Esempio n. 27
0
        /// <summary>
        /// Broad-phase callback.
        /// </summary>
        /// <param name="proxyUserDataA"></param>
        /// <param name="proxyUserDataB"></param>
        public void AddPair(object proxyUserDataA, object proxyUserDataB)
        {
            FixtureProxy proxyA = (FixtureProxy)proxyUserDataA;
            FixtureProxy proxyB = (FixtureProxy)proxyUserDataB;

            Fixture fixtureA = proxyA.Fixture;
            Fixture fixtureB = proxyB.Fixture;

            int indexA = proxyA.ChildIndex;
            int indexB = proxyB.ChildIndex;

            Body bodyA = fixtureA.Body;
            Body bodyB = fixtureB.Body;

            // Are the fixtures on the same body?
            if (bodyA == bodyB)
            {
                return;
            }

            // TODO_ERIN use a hash table to remove a potential bottleneck when both
            // bodies have a lot of contacts.
            // Does a contact already exist?
            ContactEdge edge = bodyB.ContactList;

            while (edge != null)
            {
                if (edge.Other == bodyA)
                {
                    Fixture fA = edge.Contact.FixtureA;
                    Fixture fB = edge.Contact.FixtureB;
                    int     iA = edge.Contact.ChildIndexA;
                    int     iB = edge.Contact.ChildIndexB;

                    if (fA == fixtureA && iA == indexA && fB == fixtureB && iB == indexB)
                    {
                        // A contact already exists.
                        return;
                    }

                    if (fA == fixtureB && iA == indexB && fB == fixtureA && iB == indexA)
                    {
                        // A contact already exists.
                        return;
                    }
                }

                edge = edge.Next;
            }

            // Does a joint override collision? is at least one body dynamic?
            if (bodyB.ShouldCollide(bodyA) == false)
            {
                return;
            }

            // Check user filtering.
            if (ContactFilter != null && ContactFilter.ShouldCollide(fixtureA, fixtureB) == false)
            {
                return;
            }

            // Call the factory.
            Contact c = pool.PopContact(fixtureA, indexA, fixtureB, indexB);

            if (c == null)
            {
                return;
            }

            // Contact creation may swap fixtures.
            fixtureA = c.FixtureA;
            fixtureB = c.FixtureB;
            bodyA    = fixtureA.Body;
            bodyB    = fixtureB.Body;

            // Insert into the world.
            c.Prev = null;
            c.Next = ContactList;
            if (ContactList != null)
            {
                ContactList.Prev = c;
            }
            ContactList = c;

            // Connect to island graph.

            // Connect to body A
            c.NodeA.Contact = c;
            c.NodeA.Other   = bodyB;

            c.NodeA.Prev = null;
            c.NodeA.Next = bodyA.ContactList;
            if (bodyA.ContactList != null)
            {
                bodyA.ContactList.Prev = c.NodeA;
            }
            bodyA.ContactList = c.NodeA;

            // Connect to body B
            c.NodeB.Contact = c;
            c.NodeB.Other   = bodyA;

            c.NodeB.Prev = null;
            c.NodeB.Next = bodyB.ContactList;
            if (bodyB.ContactList != null)
            {
                bodyB.ContactList.Prev = c.NodeB;
            }
            bodyB.ContactList = c.NodeB;

            // wake up the bodies
            bodyA.Awake = true;
            bodyB.Awake = true;

            ++ContactCount;
        }
Esempio n. 28
0
        public void Update(GameTime gameTime)
        {
            world.Step((float)gameTime.ElapsedGameTime.TotalSeconds, 10, 10);

            if (world.ContactCount > 0)
            {
                for (ContactEdge ce = ship.GetContactList(); ce != null; ce = ce.Next)
                {
                    bool otherHasExceeded = false;
                    foreach (Asteroid a in asteroids)
                    {
                        if (a.VelocityExceeded && !a.IsBodyDestroyed)
                        {
                            otherHasExceeded = true;
                        }
                    }

                    if (ce.Other.GetUserData() is Asteroid)
                    {
                        ((Asteroid)ce.Other.GetUserData()).Destroy("Ship" + (otherHasExceeded ? "2" : ""));
                    }
                }

                for (Contact c = world.GetContactList(); c != null; c = c.GetNext())
                {
                    Body a = c.GetFixtureA().GetBody(), b = c.GetFixtureB().GetBody();
                    if (a.GetUserData() is Asteroid && b.GetUserData() is Asteroid)
                    {
                        if (((Asteroid)a.GetUserData()).VelocityExceeded)
                        {
                            ((Asteroid)b.GetUserData()).Destroy("Other");
                        }

                        else if (((Asteroid)b.GetUserData()).VelocityExceeded)
                        {
                            ((Asteroid)a.GetUserData()).Destroy("Other");
                        }
                    }
                }
            }

            List <Asteroid> toRemove = new List <Asteroid>();

            foreach (Asteroid a in asteroids)
            {
                Bonus bonus = a.GetBonus();
                if (bonus != Bonus.None)
                {
                    bonuses.Add(bonus);
                    Score += a.Score * (int)bonus;

                    fuel = Math.Min(fuel + a.Score * (int)bonus * 0.0015f, MaxFuel);
                }

                if (a.body.Position.Y - ship.Position.Y > BackClearance)
                {
                    a.NotVisible();
                }

                if (a.IsNotVisible)
                {
                    toRemove.Add(a);
                }
            }

            foreach (Asteroid a in toRemove)
            {
                asteroids.Remove(a);
            }

            if (fuel <= 0 && ship.GetLinearVelocity().Length() < 1f)
            {
                IsLevelUp = true;
            }

            float movement = ship.Position.Y - (cameraPosY + FrontClearance);

            cameraPosY = cameraPosY + movement;
            cameraPosY = MathHelper.Clamp
                             (cameraPosY, 0, TileHeight * Height - 600);

            if (cameraPosY == 0)
            {
                ship.Position   = new Vector2(ship.Position.X, originalShipPos.Y);
                asteroidsCount += 2;
                LoadAsteroidField((int)Math.Floor(asteroidsCount));
            }
        }
Esempio n. 29
0
        private void ProcessRemovedBodies()
        {
            if (_bodyRemoveList.Count > 0)
            {
                foreach (Body body in _bodyRemoveList)
                {
                    Debug.Assert(BodyList.Count > 0);

                    // You tried to remove a body that is not contained in the BodyList.
                    // Are you removing the body more than once?
                    Debug.Assert(BodyList.Contains(body));

                    // Delete the attached joints.
                    if (body.JointList != null)
                    {
                        JointEdge je = body.JointList;

                        while (je != null)
                        {
                            JointEdge je0 = je;
                            je = je.Next;

                            RemoveJoint(je0.Joint, false);
                        }

                        body.JointList = null;
                    }

                    // Delete the attached contacts.
                    ContactEdge ce = body.ContactList;

                    while (ce != null)
                    {
                        ContactEdge ce0 = ce;
                        ce = ce.Next;

                        ContactManager.Destroy(ce0.Contact);
                    }


                    body.ContactList = null;

                    // Delete the attached fixtures. This destroys broad-phase proxies.
                    if (body.FixtureList != null)
                    {
                        for (int i = 0; i < body.FixtureList.Count; i++)
                        {
                            body.FixtureList[i].DestroyProxies(ContactManager.BroadPhase);
                            body.FixtureList[i].Destroy();
                        }
                    }

                    body.FixtureList = null;

                    // Remove world body list.
                    BodyList.Remove(body);

                    BodyRemoved?.Invoke(body);
                }

                _bodyRemoveList.Clear();
            }
        }
Esempio n. 30
0
        private void HandleSubCollision(Contact contact, Submarine otherSub)
        {
            Debug.Assert(otherSub != submarine);

            Vector2 normal;
            FixedArray2 <Vector2> points;

            contact.GetWorldManifold(out normal, out points);
            if (contact.FixtureA.Body == otherSub.SubBody.Body.FarseerBody)
            {
                normal = -normal;
            }

            float thisMass  = Body.Mass + submarine.DockedTo.Sum(s => s.PhysicsBody.Mass);
            float otherMass = otherSub.PhysicsBody.Mass + otherSub.DockedTo.Sum(s => s.PhysicsBody.Mass);
            float massRatio = otherMass / (thisMass + otherMass);

            float impact = (Vector2.Dot(Velocity - otherSub.Velocity, normal) / 2.0f) * massRatio;

            //apply impact to this sub (the other sub takes care of this in its own collision callback)
            ApplyImpact(impact, normal, contact);
            foreach (Submarine dockedSub in submarine.DockedTo)
            {
                dockedSub.SubBody.ApplyImpact(impact, normal, contact);
            }

            //find all contacts between this sub and level walls
            List <Contact> levelContacts = new List <Contact>();
            ContactEdge    contactEdge   = Body.FarseerBody.ContactList;

            while (contactEdge.Next != null)
            {
                if (contactEdge.Contact.Enabled &&
                    contactEdge.Other.UserData is VoronoiCell &&
                    contactEdge.Contact.IsTouching)
                {
                    levelContacts.Add(contactEdge.Contact);
                }

                contactEdge = contactEdge.Next;
            }

            if (levelContacts.Count == 0)
            {
                return;
            }

            //if this sub is in contact with the level, apply artifical impacts
            //to both subs to prevent the other sub from bouncing on top of this one
            //and to fake the other sub "crushing" this one against a wall
            Vector2 avgContactNormal = Vector2.Zero;

            foreach (Contact levelContact in levelContacts)
            {
                Vector2 contactNormal;
                FixedArray2 <Vector2> temp;
                levelContact.GetWorldManifold(out contactNormal, out temp);

                //if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal
                VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
                                   ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);

                var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center;
                if (Vector2.Dot(contactNormal, cellDiff) < 0)
                {
                    contactNormal = -contactNormal;
                }

                avgContactNormal += contactNormal;

                //apply impacts at the positions where this sub is touching the level
                ApplyImpact((Vector2.Dot(Velocity - otherSub.Velocity, contactNormal) / 2.0f) * massRatio / levelContacts.Count, contactNormal, levelContact);
            }
            avgContactNormal /= levelContacts.Count;

            //apply an impact to the other sub
            float contactDot = Vector2.Dot(otherSub.PhysicsBody.LinearVelocity, -avgContactNormal);

            if (contactDot > 0.0f)
            {
                otherSub.PhysicsBody.LinearVelocity -= Vector2.Normalize(otherSub.PhysicsBody.LinearVelocity) * contactDot;

                impact = Vector2.Dot(otherSub.Velocity, normal);
                otherSub.SubBody.ApplyImpact(impact, normal, contact);
                foreach (Submarine dockedSub in otherSub.DockedTo)
                {
                    dockedSub.SubBody.ApplyImpact(impact, normal, contact);
                }
            }
        }
Esempio n. 31
0
        public override void earlyUpdate()
        {
            base.earlyUpdate();
            float dd = 0;

            if (neg)
            {
                dd = 180;
            }
            //Console.WriteLine(MyMath.AngleDistance(MyMath.AngleBetween(pos, obj2.pos), dd));
            if (Controls.GetKey(Keys.Space) == Controls.Pressed || Controls.GetButton(Buttons.A) == Controls.Pressed)
            {
                ContactEdge c = body.ContactList;
                if (c != null)
                {
                    body.ApplyLinearImpulse(new Vector2(0, -150));
                    Console.WriteLine(c.Contact.IsTouching());
                }
            }
            if (doc.controls.getKey(Keys.Left) == Controls.Held || Controls.GetButton(Buttons.LeftThumbstickLeft) == Controls.Held)
            {
                if (body.GetLinearVelocityFromLocalPoint(new Vector2(x, y)).X > -topspeed && !swinging)
                {
                    body.ApplyLinearImpulse(new Vector2(-4.5f, 0));
                }
                //Console.WriteLine(body.GetLinearVelocityFromLocalPoint(new Vector2(x, y)));
                neg = false;
            }
            if (doc.controls.getKey(Keys.Right) == Controls.Held || Controls.GetButton(Buttons.LeftThumbstickRight) == Controls.Held)
            {
                if (body.GetLinearVelocityFromLocalPoint(new Vector2(x, y)).X < topspeed && !swinging)
                {
                    body.ApplyLinearImpulse(new Vector2(4.5f, 0));
                }
                neg = true;
            }
            if (Controls.GetKey(Keys.R) == Controls.Pressed || Controls.GetButton(Buttons.RightShoulder) == Controls.Pressed)
            {
                //whipTo(obj2);
                Obj   ob   = null;
                float dist = 700;
                float ab;
                float d = 0;
                if (neg)
                {
                    d = 180;
                }
                bool  nodir = false;
                float yy    = y;
                if (Controls.GetKey(Keys.Right) != Controls.Held && Controls.GetKey(Keys.Left) != Controls.Held)
                {
                    nodir = true;
                }
                for (int i = 0; i < doc.objList.Count; i++)
                {
                    Obj o = doc.objList[i];
                    ab = Math.Abs(MyMath.AngleDistance(MyMath.AngleBetween(pos, o.pos), d));
                    if (o.type == Obj.PointType.SwingPoint && o.body != null && MyMath.Distance(pos, o.pos) < dist && o.y < yy && (ab < 95 || nodir))
                    {
                        Console.WriteLine(ab);
                        dist = MyMath.Distance(pos, o.pos);
                        ob   = o;
                    }
                }
                if (ob != null)
                {
                    whipTo(ob);
                }
            }
            else if (doc.controls.getKey(Keys.R) == Controls.Held)
            {
                //This is the Whipping which is context based.

                //Search area in front of Player


                //Grab nearest point and run code for it.

                /*float minDist = radius;
                 * for (int index = 0; index < doc.objList.Count; index++)
                 * {
                 *  //check distance
                 *  if (doc.objList[index].type != PointType.Normal && MyMath.Distance(pos, doc.objList[index].pos) < minDist)
                 *  {
                 *      minDist = MyMath.Distance(pos, doc.objList[index].pos);
                 *      Point = doc.objList[index];
                 *  }
                 * }
                 * if (Point == null) return;
                 * if (Point.type == PointType.SwingPoint)
                 * {
                 *  swing(Point);
                 * }
                 * else if (Point.type == PointType.SlingPoint)
                 * {
                 *  sling(Point);
                 * }
                 * else if (Point.type == PointType.Pullblock)
                 * {
                 *  pull(Point);
                 * }*/
            }
            if (Controls.GetKey(Keys.R) == Controls.Released || Controls.GetButton(Buttons.RightShoulder) == Controls.Released)
            {
                endWhip();
            }
            //Console.WriteLine(body.GetLinearVelocityFromLocalPoint(new Vector2(x, y)));
            //Console.WriteLine(body.Friction);
        }