示例#1
0
        public static void ComponentActivate(cpBody root)
        {
            if (root == null || !root.IsSleeping())
            {
                return;
            }
            cp.AssertHard(!root.IsRogue(), "Internal Error: componentActivate() called on a rogue body.");

            var    space = root.space;
            cpBody body  = root;

            while (body != null)
            {
                var next = body.nodeNext;

                body.nodeIdleTime = 0;
                body.nodeRoot     = null;
                body.nodeNext     = null;

                space.ActivateBody(body);

                body = next;
            }

            space.sleepingComponents.Remove(root);
        }
示例#2
0
        // Hashset filter func to throw away old arbiters.
        public bool ArbiterSetFilter(cpArbiter arb)
        {
            var ticks = this.stamp - arb.stamp;

            cpBody a = arb.body_a, b = arb.body_b;

            // TODO should make an arbiter state for this so it doesn't require filtering arbiters for
            // dangling body pointers on body removal.
            // Preserve arbiters on sensors and rejected arbiters for sleeping objects.
            // This prevents errant separate callbacks from happenening.
            if (
                (a.bodyType == cpBodyType.STATIC || a.IsSleeping()) &&
                (b.bodyType == cpBodyType.STATIC || b.IsSleeping())
                )
            {
                return(true);
            }

            // Arbiter was used last frame, but not this one
            if (ticks >= 1 && arb.state != cpArbiterState.Cached)
            {
                arb.state = cpArbiterState.Cached;

                arb.handler.separateFunc(arb, this, arb.handler.userData);
            }

            if (ticks >= this.collisionPersistence)
            {
                arb.contacts.Clear();
                //cpArrayPush(this.pooledArbiters, arb);
                return(false);
            }

            return(true);
        }
        // Defined in cpSpace.c
        // Wake up a sleeping or idle body.
        public void Activate()
        {
            if (bodyType == cpBodyType.DYNAMIC)
            {
                nodeIdleTime = 0.0f;

                cpBody root = nodeRoot;
                if (root != null && root.IsSleeping())
                {
                    // TODO should cpBodyIsSleeping(root) be an assertion?
                    cp.AssertSoft(root.bodyType == cpBodyType.DYNAMIC, "Internal Error: Non-dynamic body component root detected.");

                    cpSpace space = root.space;
                    cpBody  body  = root;
                    while (body != null)
                    {
                        cpBody next = body.nodeNext;

                        body.nodeIdleTime = 0.0f;
                        body.nodeRoot     = null;
                        body.nodeNext     = null;
                        space.ActivateBody(body);

                        body = next;
                    }

                    space.sleepingComponents.Remove(root);
                }

                eachArbiter((arb, o) =>
                {
                    // Reset the idle timer of things the body is touching as well.
                    // That way things don't get left hanging in the air.
                    cpBody other = (arb.body_a == this ? arb.body_b : arb.body_a);
                    if (other.bodyType != cpBodyType.STATIC)
                    {
                        other.nodeIdleTime = 0.0f;
                    }
                }, null);
            }
        }
        // Force a body to fall asleep immediately along with other bodies in a group.
        public void SleepWithGroup(cpBody group)
        {
            cp.AssertHard(bodyType == cpBodyType.DYNAMIC, "Non-dynamic bodies cannot be put to sleep.");

            var space = this.space;

            cp.AssertHard(!space.IsLocked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback.");
            cp.AssertHard(space.GetSleepTimeThreshold() < cp.Infinity, "Sleeping is not enabled on the space. You cannot sleep a body without setting a sleep time threshold on the space.");
            cp.AssertHard(group == null || group.IsSleeping(), "Cannot use a non-sleeping body as a group identifier.");

            if (this.IsSleeping())
            {
                cp.AssertSoft(cp.ComponentRoot(this) == cp.ComponentRoot(group), "The body is already sleeping and it's group cannot be reassigned.");
                return;
            }

            eachShape((shape, o) => shape.CacheBB(), null);


            space.DeactivateBody(this);

            if (group != null)
            {
                var root = cp.ComponentRoot(group);

                this.nodeRoot     = root;
                this.nodeNext     = root.nodeNext;
                this.nodeIdleTime = 0;

                root.nodeNext = this;
            }
            else
            {
                this.nodeRoot     = this;
                this.nodeNext     = null;
                this.nodeIdleTime = 0;

                space.sleepingComponents.Add(this);
            }
            space.dynamicBodies.Remove(this);
        }
示例#5
0
        public void ProcessComponents(float dt)
        {
            var sleep  = (this.sleepTimeThreshold != cp.Infinity);
            var bodies = this.dynamicBodies;

            // These checks can be removed at some stage (if DEBUG == undefined)
            for (var i = 0; i < bodies.Count; i++)
            {
                var body = bodies[i];

                cp.AssertSoft(body.nodeNext == null, "Internal Error: Dangling next pointer detected in contact graph.");
                cp.AssertSoft(body.nodeRoot == null, "Internal Error: Dangling root pointer detected in contact graph.");
            }

            // Calculate the kinetic energy of all the bodies
            if (sleep)
            {
                var dv   = this.idleSpeedThreshold;
                var dvsq = (dv != 0 ? dv * dv : cpVect.cpvlengthsq(this.gravity) * dt * dt);

                for (var i = 0; i < bodies.Count; i++)
                {
                    // TODO should make a separate array for kinematic bodies.
                    if (bodies[i].bodyType != cpBodyType.DYNAMIC)
                    {
                        continue;
                    }

                    // Need to deal with infinite mass objects
                    var keThreshold = (dvsq > 0 ? bodies[i].m * dvsq : 0.0f);
                    bodies[i].nodeIdleTime = (bodies[i].KineticEnergy() > keThreshold ? 0 : bodies[i].nodeIdleTime + dt);
                }
            }

            // Awaken any sleeping bodies found and then push arbiters to the bodies' lists.

            List <cpArbiter> arbiters = this.arbiters; // new List<cpArbiter>();
            var count = arbiters.Count;                //FIX: we cannot read the count values of the array because it changes inside

            for (int i = 0; i < count; i++)
            {
                cpArbiter arb = arbiters[i];
                cpBody    a = arb.body_a, b = arb.body_b;

                if (sleep)
                {
                    if (b.bodyType == cpBodyType.KINEMATIC || a.IsSleeping())
                    {
                        a.Activate();
                    }

                    if (a.bodyType == cpBodyType.KINEMATIC || b.IsSleeping())
                    {
                        b.Activate();
                    }
                }

                a.PushArbiter(arb);
                b.PushArbiter(arb);
            }

            if (sleep)
            {
                // Bodies should be held active if connected by a joint to a non-static rouge body.
                var constraints = this.constraints;
                for (var i = 0; i < constraints.Count; i++)
                {
                    cpConstraint constraint = constraints[i];
                    cpBody       a = constraint.a, b = constraint.b;

                    if (b.bodyType == cpBodyType.KINEMATIC)
                    {
                        a.Activate();
                    }

                    if (a.bodyType == cpBodyType.KINEMATIC)
                    {
                        b.Activate();
                    }
                }

                // Generate components and deactivate sleeping ones
                for (var i = 0; i < bodies.Count;)
                {
                    var body = bodies[i];

                    if (cp.ComponentRoot(body) == null)
                    {
                        // Body not in a component yet. Perform a DFS to flood fill mark
                        // the component in the contact graph using this body as the root.
                        FloodFillComponent(body, body);

                        // Check if the component should be put to sleep.
                        if (!ComponentActive(body, this.sleepTimeThreshold))
                        {
                            this.sleepingComponents.Add(body);
                            //CP_BODY_FOREACH_COMPONENT
                            for (var other = body; other != null; other = other.nodeNext)
                            {
                                this.DeactivateBody(other);
                            }

                            // deactivateBody() removed the current body from the list.
                            // Skip incrementing the index counter.
                            continue;
                        }
                    }

                    i++;

                    // Only sleeping bodies retain their component node pointers.
                    body.nodeRoot = null;
                    body.nodeNext = null;
                }
            }
        }