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); }
// 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); }
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; } } }