예제 #1
0
        protected Joint(JointDef def)
        {
            _type             = def.type;
            _bodyA            = def.body1;
            _bodyB            = def.body2;
            _collideConnected = def.collideConnected;
            _userData         = def.userData;

            _edgeA = new JointEdge();
            _edgeB = new JointEdge();
        }
예제 #2
0
        // This is used to prevent connected bodies from colliding.
        // It may lie, depending on the collideConnected flag.
        internal bool IsConnected(Body other)
        {
            for (JointEdge jn = _jointList; jn != null; jn = jn.Next)
            {
                if (jn.Other == other)
                {
                    return(jn.Joint._collideConnected == false);
                }
            }

            return(false);
        }
예제 #3
0
        void SolveTOI(ref TimeStep step)
        {
            // Reserve an island and a queue for TOI island solution.
            _island.Reset(_bodyCount,
                          Settings.b2_maxTOIContactsPerIsland,
                          Settings.b2_maxTOIJointsPerIsland,
                          _contactManager.ContactListener);

            //Simple one pass queue
            //Relies on the fact that we're only making one pass
            //through and each body can only be pushed/popped once.
            //To push:
            //  queue[queueStart+queueSize++] = newElement;
            //To pop:
            //	poppedElement = queue[queueStart++];
            //  --queueSize;
//#warning More Body array Allocs
            int queueCapacity = _bodyCount;

            Body[] queue = new Body[_bodyCount];

            for (Body b = _bodyList; b != null; b = b._next)
            {
                b._flags   &= ~BodyFlags.Island;
                b._sweep.t0 = 0.0f;
            }

            for (Contact c = _contactManager._contactList; c != null; c = c._next)
            {
                // Invalidate TOI
                c._flags &= ~(ContactFlags.Toi | ContactFlags.Island);
            }

            for (Joint j = _jointList; j != null; j = j._next)
            {
                j._islandFlag = false;
            }

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

                for (Contact c = _contactManager._contactList; c != null; c = c._next)
                {
                    if ((c._flags & (ContactFlags.Slow | ContactFlags.NonSolid)) != ContactFlags.None)
                    {
                        continue;
                    }

                    // TODO_ERIN keep a counter on the contact, only respond to M TOIs per contact.

                    float toi = 1.0f;
                    if ((c._flags & ContactFlags.Toi) != ContactFlags.None)
                    {
                        // This contact has a valid cached TOI.
                        toi = c._toi;
                    }
                    else
                    {
                        // Compute the TOI for this contact.
                        Fixture s1 = c.GetFixtureA();
                        Fixture s2 = c.GetFixtureB();
                        Body    b1 = s1.GetBody();
                        Body    b2 = s2.GetBody();

                        if ((b1.IsStatic || b1.IsSleeping) && (b2.IsStatic || b2.IsSleeping))
                        {
                            continue;
                        }

                        // Put the sweeps onto the same time interval.
                        float t0 = b1._sweep.t0;

                        if (b1._sweep.t0 < b2._sweep.t0)
                        {
                            t0 = b2._sweep.t0;
                            b1._sweep.Advance(t0);
                        }
                        else if (b2._sweep.t0 < b1._sweep.t0)
                        {
                            t0 = b1._sweep.t0;
                            b2._sweep.Advance(t0);
                        }

                        Debug.Assert(t0 < 1.0f);

                        // Compute the time of impact.
                        toi = c.ComputeTOI(ref b1._sweep, ref b2._sweep);
                        //CalculateTimeOfImpact(c._fixtureA.GetShape(), b1._sweep, c._fixtureB.GetShape(), b2._sweep);

                        Debug.Assert(0.0f <= toi && toi <= 1.0f);

                        // If the TOI is in range ...
                        if (0.0f < toi && toi < 1.0f)
                        {
                            // Interpolate on the actual range.
                            toi = Math.Min((1.0f - toi) * t0 + toi, 1.0f);
                        }


                        c._toi    = toi;
                        c._flags |= ContactFlags.Toi;
                    }

                    if (Settings.b2_FLT_EPSILON < toi && toi < minTOI)
                    {
                        // This is the minimum TOI found so far.
                        minContact = c;
                        minTOI     = toi;
                    }
                }

                if (minContact == null || 1.0f - 100.0f * Settings.b2_FLT_EPSILON < minTOI)
                {
                    // No more TOI events. Done!
                    break;
                }

                // Advance the bodies to the TOI.
                Fixture s1_2 = minContact.GetFixtureA();
                Fixture s2_2 = minContact.GetFixtureB();
                Body    b1_2 = s1_2.GetBody();
                Body    b2_2 = s2_2.GetBody();
                b1_2.Advance(minTOI);
                b2_2.Advance(minTOI);

                // The TOI contact likely has some new contact points.
                minContact.Update(_contactManager.ContactListener);
                minContact._flags &= ~ContactFlags.Toi;

                if ((minContact._flags & ContactFlags.Touch) == 0)
                {
                    // This shouldn't happen. Numerical error?
                    //Debug.Assert(false);
                    continue;
                }

                // Build the TOI island. We need a dynamic seed.
                Body seed = b1_2;
                if (seed.IsStatic)
                {
                    seed = b2_2;
                }

                // Reset island and queue.
                _island.Clear();

                int queueStart = 0;         // starting index for queue
                int queueSize  = 0;         // elements in queue
                queue[queueStart + queueSize++] = seed;
                seed._flags |= BodyFlags.Island;

                // Perform a breadth first search (BFS) on the contact/joint graph.
                while (queueSize > 0)
                {
                    // Grab the next body off the stack and add it to the island.
                    Body b = queue[queueStart++];
                    --queueSize;

                    _island.Add(b);

                    // Make sure the body is awake.
                    b._flags &= ~BodyFlags.Sleep;

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

                    // Search all contacts connected to this body.
                    for (ContactEdge cEdge = b._contactList; cEdge != null; cEdge = cEdge.Next)
                    {
                        // Does the TOI island still have space for contacts?
                        if (_island._contacts.Count == _island._contactCapacity)
                        {
                            continue;
                        }

                        // Has this contact already been added to an island? Skip slow or non-solid contacts.
                        if ((cEdge.Contact._flags & (ContactFlags.Island | ContactFlags.Slow | ContactFlags.NonSolid)) != ContactFlags.None)
                        {
                            continue;
                        }

                        // Is this contact touching? For performance we are not updating this contact.
                        if ((cEdge.Contact._flags & ContactFlags.Touch) == 0)
                        {
                            continue;
                        }

                        _island.Add(cEdge.Contact);
                        cEdge.Contact._flags |= ContactFlags.Island;

                        // Update other body.
                        Body other = cEdge.Other;

                        // Was the other body already added to this island?
                        if ((other._flags & BodyFlags.Island) != BodyFlags.None)
                        {
                            continue;
                        }

                        // March forward, this can do no harm since this is the min TOI.
                        if (other.IsStatic == false)
                        {
                            other.Advance(minTOI);
                            other.WakeUp();
                        }

                        Debug.Assert(queueStart + queueSize < queueCapacity);
                        queue[queueStart + queueSize] = other;
                        ++queueSize;
                        other._flags |= BodyFlags.Island;
                    }

                    for (JointEdge jEdge = b._jointList; jEdge != null; jEdge = jEdge.Next)
                    {
                        if (_island._jointCount == _island._jointCapacity)
                        {
                            continue;
                        }

                        if (jEdge.Joint._islandFlag == true)
                        {
                            continue;
                        }

                        _island.Add(jEdge.Joint);

                        jEdge.Joint._islandFlag = true;

                        Body other = jEdge.Other;

                        if ((other._flags & BodyFlags.Island) != BodyFlags.None)
                        {
                            continue;
                        }

                        if (!other.IsStatic)
                        {
                            other.Advance(minTOI);
                            other.WakeUp();
                        }

                        Debug.Assert(queueStart + queueSize < queueCapacity);
                        queue[queueStart + queueSize] = other;
                        ++queueSize;
                        other._flags |= BodyFlags.Island;
                    }
                }

                TimeStep subStep;
                subStep.warmStarting       = false;
                subStep.dt                 = (1.0f - minTOI) * step.dt;
                subStep.inv_dt             = 1.0f / subStep.dt;
                subStep.dtRatio            = 0.0f;
                subStep.velocityIterations = step.velocityIterations;
                subStep.positionIterations = step.positionIterations;

                _island.SolveTOI(ref subStep);

                // Post solve cleanup.
                for (int i = 0; i < _island._bodyCount; ++i)
                {
                    // Allow bodies to participate in future TOI islands.
                    Body b = _island._bodies[i];
                    b._flags &= ~BodyFlags.Island;

                    if ((b._flags & (BodyFlags.Sleep | BodyFlags.Frozen)) != BodyFlags.None)
                    {
                        continue;
                    }

                    if (b.IsStatic)
                    {
                        continue;
                    }

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

                    // Invalidate all contact TOIs associated with this body. Some of these
                    // may not be in the island because they were not touching.
                    for (ContactEdge ce = b._contactList; ce != null; ce = ce.Next)
                    {
                        ce.Contact._flags &= ~ContactFlags.Toi;
                    }
                }

                int contactCount = _island._contacts.Count;
                for (int i = 0; i < contactCount; ++i)
                {
                    // Allow contacts to participate in future TOI islands.
                    Contact c = _island._contacts[i];
                    c._flags &= ~(ContactFlags.Toi | ContactFlags.Island);
                }

                for (int i = 0; i < _island._jointCount; ++i)
                {
                    // Allow joints to participate in future TOI islands.
                    Joint j = _island._joints[i];
                    j._islandFlag = false;
                }

                // Commit fixture proxy movements to the broad-phase so that new contacts are created.
                // Also, some contacts can be destroyed.
                _contactManager.FindNewContacts();
            }
        }
예제 #4
0
        void Solve(ref TimeStep step)
        {
            // Size the island for the worst case.
            _island.Reset(_bodyCount,
                          _contactManager._contactCount,
                          _jointCount,
                          _contactManager.ContactListener);

            // Clear all the island flags.
            for (Body b = _bodyList; b != null; b = b._next)
            {
                b._flags &= ~BodyFlags.Island;
            }
            for (Contact c = _contactManager._contactList; c != null; c = c._next)
            {
                c._flags &= ~ContactFlags.Island;
            }
            for (Joint j = _jointList; j != null; j = j._next)
            {
                j._islandFlag = false;
            }

            // Build and simulate all awake islands.
//#warning Remove extra allocs

            int stackSize = _bodyCount;

            Body[] stack = new Body[_bodyCount];
            for (Body seed = _bodyList; seed != null; seed = seed._next)
            {
                if ((seed._flags & (BodyFlags.Island | BodyFlags.Sleep | BodyFlags.Frozen)) != BodyFlags.None)
                {
                    continue;
                }

                if (seed.IsStatic)
                {
                    continue;
                }

                // Reset island and stack.
                _island.Clear();
                int stackCount = 0;
                stack[stackCount++] = seed;
                seed._flags        |= BodyFlags.Island;

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

                    // Make sure the body is awake.
                    b._flags &= ~BodyFlags.Sleep;

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

                    // Search all contacts connected to this body.
                    for (ContactEdge ce = b._contactList; ce != null; ce = ce.Next)
                    {
                        // Has this contact already been added to an island?
                        // Is this contact non-solid (involves a sensor).
                        if ((ce.Contact._flags & (ContactFlags.Island | ContactFlags.NonSolid)) != ContactFlags.None)
                        {
                            continue;
                        }

                        // Is this contact touching?
                        if ((ce.Contact._flags & ContactFlags.Touch) == ContactFlags.None)
                        {
                            continue;
                        }

                        _island.Add(ce.Contact);
                        ce.Contact._flags |= ContactFlags.Island;

                        Body other = ce.Other;

                        // Was the other body already added to this island?
                        if ((other._flags & BodyFlags.Island) != BodyFlags.None)
                        {
                            continue;
                        }

                        Debug.Assert(stackCount < stackSize);
                        stack[stackCount++] = other;
                        other._flags       |= BodyFlags.Island;
                    }

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

                        _island.Add(je.Joint);
                        je.Joint._islandFlag = true;

                        Body other = je.Other;
                        if ((other._flags & BodyFlags.Island) != BodyFlags.None)
                        {
                            continue;
                        }

                        Debug.Assert(stackCount < stackSize);
                        stack[stackCount++] = other;
                        other._flags       |= BodyFlags.Island;
                    }
                }

                _island.Solve(ref step, Gravity, _allowSleep);

                // 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.IsStatic)
                    {
                        b._flags &= ~BodyFlags.Island;
                    }
                }
            }

            // Synchronize fixtures, check for out of range bodies.
            for (Body b = _bodyList; b != null; b = b.GetNext())
            {
                if ((b._flags & (BodyFlags.Sleep | BodyFlags.Frozen)) != BodyFlags.None)
                {
                    continue;
                }

                if (b.IsStatic)
                {
                    continue;
                }

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

            // Look for new contacts.
            _contactManager.FindNewContacts();
        }
예제 #5
0
        /// Destroy a rigid body given a definition. No reference to the definition
        /// is retained. This function is locked during callbacks.
        /// @warning This automatically deletes all associated shapes and joints.
        /// @warning This function is locked during callbacks.
        public void DestroyBody(Body b)
        {
            Debug.Assert(_bodyCount > 0);
            Debug.Assert(!IsLocked);
            if (IsLocked)
            {
                return;
            }

            // Delete the attached joints.
            JointEdge je = b._jointList;

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

                if (DestructionListener != null)
                {
                    DestructionListener.SayGoodbye(je0.Joint);
                }

                DestroyJoint(je0.Joint);
            }
            b._jointList = null;

            // Delete the attached contacts.
            ContactEdge ce = b._contactList;

            while (ce != null)
            {
                ContactEdge ce0 = ce;
                ce = ce.Next;
                _contactManager.Destroy(ce0.Contact);
            }
            b._contactList = null;

            // Delete the attached fixtures. This destroys broad-phase proxies.
            Fixture f = b._fixtureList;

            while (f != null)
            {
                Fixture f0 = f;
                f = f._next;

                if (DestructionListener != null)
                {
                    DestructionListener.SayGoodbye(f0);
                }

                f0.Destroy(_contactManager._broadPhase);
            }
            b._fixtureList  = null;
            b._fixtureCount = 0;

            // Remove world body list.
            if (b._prev != null)
            {
                b._prev._next = b._next;
            }

            if (b._next != null)
            {
                b._next._prev = b._prev;
            }

            if (b == _bodyList)
            {
                _bodyList = b._next;
            }

            --_bodyCount;
        }
예제 #6
0
파일: Body.cs 프로젝트: Nukepayload2/Box2D
        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;
        }
예제 #7
0
파일: Joint.cs 프로젝트: Nukepayload2/Box2D
        protected Joint(JointDef def)
        {
            _type = def.type;
            _bodyA = def.body1;
            _bodyB = def.body2;
            _collideConnected = def.collideConnected;
            _userData = def.userData;

            _edgeA = new JointEdge();
            _edgeB = new JointEdge();
        }