// Find TOI contacts and solve them. public void SolveTOI(b2TimeStep step) { b2Island island = new b2Island(2 * b2Settings.b2_maxTOIContacts, b2Settings.b2_maxTOIContacts, 0, m_contactManager.ContactListener); if (m_stepComplete) { for (b2Body b = m_bodyList; b; b = b.Next) { b.BodyFlags &= ~b2Body.e_islandFlag; b.m_sweep.alpha0 = 0.0f; } for (b2Contact c = m_contactManager.ContactList; c; c = c.Next) { // Invalidate TOI c.ContactFlags &= ~(b2ContactType.e_toiFlag | b2ContactType.e_islandFlag); c.m_toiCount = 0; c.m_toi = 1.0f; } } // Find TOI events and solve them. for (; ;) { // Find the first TOI. b2Contact minContact = null; float minAlpha = 1.0f; for (b2Contact c = m_contactManager.ContactList; c != null; c = c.Next) { // Is this contact disabled? if (c.IsEnabled() == false) { continue; } // Prevent excessive sub-stepping. if (c.m_toiCount > b2Settings.b2_maxSubSteps) { continue; } float alpha = 1.0f; if (c.ContactFlags.HasFlag(b2ContactFlags.e_toiFlag)) { // This contact has a valid cached TOI. alpha = c.m_toi; } else { b2Fixture fA = c.GetFixtureA(); b2Fixture fB = c.GetFixtureB(); // Is there a sensor? if (fA.IsSensor || fB.IsSensor) { continue; } b2Body bA = fA.Body; b2Body bB = fB.Body; b2BodyType typeA = bA.BodyType; b2BodyType typeB = bB.BodyType; bool activeA = bA.IsAwake() && typeA != b2BodyType.b2_staticBody; bool activeB = bB.IsAwake() && typeB != b2BodyType.b2_staticBody; // Is at least one body active (awake and dynamic or kinematic)? if (activeA == false && activeB == false) { continue; } bool collideA = bA.IsBullet() || typeA != b2BodyType.b2_dynamicBody; bool collideB = bB.IsBullet() || typeB != b2BodyType.b2_dynamicBody; // 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); } int indexA = c.GetChildIndexA(); int indexB = c.GetChildIndexB(); // Compute the time of impact in interval [0, minTOI] b2TOIInput input = new b2TOIInput(); input.proxyA.Set(fA.Shape, indexA); input.proxyB.Set(fB.Shape, indexB); input.sweepA = bA.Sweep; input.sweepB = bB.Sweep; input.tMax = 1.0f; b2TOIOutput output = b2TimeOfImpact(input); // Beta is the fraction of the remaining portion of the . float beta = output.t; if (output.state == b2TOIOutputType.e_touching) { alpha = b2Math.b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); } else { alpha = 1.0f; } c.m_toi = alpha; c.ContactFlags |= b2ContactFlags.e_toiFlag; } if (alpha < minAlpha) { // This is the minimum TOI found so far. minContact = c; minAlpha = alpha; } } if (minContact == null || 1.0f - 10.0f * b2Settings.b2_epsilon < minAlpha) { // No more TOI events. Done! m_stepComplete = true; break; } { // Advance the bodies to the TOI. b2Fixture fA = minContact.GetFixtureA(); b2Fixture fB = minContact.GetFixtureB(); b2Body bA = fA.Body; b2Body bB = fB.Body; b2Sweep backup1 = bA.Sweep; b2Sweep backup2 = bB.Sweep; bA.Advance(minAlpha); bB.Advance(minAlpha); // The TOI contact likely has some new contact points. minContact.Update(m_contactManager.ContactListener); minContact.ContactFlags &= ~b2ContactFlags.e_toiFlag; ++minContact.m_toiCount; // Is the contact solid? if (minContact.IsEnabled() == false || minContact.IsTouching() == false) { // Restore the sweeps. minContact.SetEnabled(false); bA.Sweep = backup1; bB.Sweep = backup2; bA.SynchronizeTransform(); bB.SynchronizeTransform(); continue; } bA.SetAwake(true); bB.SetAwake(true); // Build the island island.Clear(); island.Add(bA); island.Add(bB); island.Add(minContact); bA.BodyFlags |= b2BodyFlags.e_islandFlag; bB.BodyFlags |= b2BodyFlags.e_islandFlag; minContact.ContentType |= b2ContactFlags.e_islandFlag; // Get contacts on bodyA and bodyB. b2Body[] bodies = new b2Body[] { bA, bB }; for (int i = 0; i < 2; ++i) { b2Body body = bodies[i]; if (body.BodyType == b2BodyType.b2_dynamicBody) { for (b2ContactEdge ce = body.ContactList; ce != null; ce = ce.next) { if (island.BodyCount == island.BodyCapacity) { break; } if (island.ContactCount == island.ContactCapacity) { break; } b2Contact contact = ce.contact; // Has this contact already been added to the island? if (contact.ContactType & b2ContactType.e_islandFlag) { continue; } // Only add static, kinematic, or bullet bodies. b2Body other = ce.other; if (other.BodyType == b2BodyType.b2_dynamicBody && body.IsBullet() == false && other.IsBullet() == false) { continue; } // Skip sensors. bool sensorA = contact.m_fixtureA.m_isSensor; bool sensorB = contact.m_fixtureB.m_isSensor; if (sensorA || sensorB) { continue; } // Tentatively advance the body to the TOI. b2Sweep backup = other.Sweep; if (other.BodyFlags.HasFlag(b2BodyFlags.e_islandFlag)) { other.Advance(minAlpha); } // Update the contact points contact.Update(m_contactManager.ContactListener); // Was the contact disabled by the user? if (contact.IsEnabled() == 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 contact.ContactFlags |= b2ContactFlags.e_islandFlag; island.Add(contact); // Has the other body already been added to the island? if (other.BodyFlags.HasFlag(b2BodyFlags.e_islandFlag)) { continue; } // Add the other body to the island. other.BodyFlags |= b2BodyFlags.e_islandFlag; if (other.BodyType != b2BodyType.b2_staticBody) { other.SetAwake(true); } island.Add(other); } } } b2TimeStep subStep; subStep.dt = (1.0f - minAlpha) * step.dt; subStep.inv_dt = 1.0f / subStep.dt; subStep.dtRatio = 1.0f; subStep.positionIterations = 20; subStep.velocityIterations = step.velocityIterations; subStep.warmStarting = false; island.SolveTOI(subStep, bA.m_islandIndex, bB.m_islandIndex); // Reset island flags and synchronize broad-phase proxies. for (int i = 0; i < island.m_bodyCount; ++i) { b2Body body = island.m_bodies[i]; body.BodyFlags &= ~b2BodyFlags.e_islandFlag; if (body.BodyType != b2BodyType.b2_dynamicBody) { continue; } body.SynchronizeFixtures(); // Invalidate all contact TOIs on this displaced body. for (b2ContactEdge ce = body.ContactList; ce != null; ce = ce.next) { ce.Contact.ContactFlags &= ~(b2ContactFlags.e_toiFlag | b2ContactFlags.e_islandFlag); } } // Commit fixture proxy movements to the broad-phase so that new contacts are created. // Also, some contacts can be destroyed. m_contactManager.FindNewContacts(); if (m_subStepping) { m_stepComplete = false; break; } } } }
// Find islands, integrate and solveraints, solve positionraints public void Solve(b2TimeStep step) { m_profile.solveInit = 0.0f; m_profile.solveVelocity = 0.0f; m_profile.solvePosition = 0.0f; // Size the island for the worst case. b2Island island = new b2Island(m_bodyCount, m_contactManager.ContactCount, m_jointCount, m_contactManager.ContactListener); // Clear all the island flags. for (b2Body b = m_bodyList; b != null; b = b.Next) { b.BodyFlags &= ~b2BodyFlags.e_islandFlag; } for (b2Contact c = m_contactManager.ContactList; c != null; c = c.Next) { c.ContactFlags &= ~b2ContactFlags.e_islandFlag; } for (b2Joint j = m_jointList; j; j = j.Next) { j.m_islandFlag = false; } // Build and simulate all awake islands. int stackSize = m_bodyCount; b2Body[] stack = new b2Body[stackSize]; for (b2Body seed = m_bodyList; seed != null; seed = seed.Next) { if (seed.BodyFlags & b2BodyFlags.e_islandFlag) { continue; } if (seed.IsAwake() == false || seed.IsActive() == false) { continue; } // The seed can be dynamic or kinematic. if (seed.BodyType == b2BodyType.b2_staticBody) { continue; } // Reset island and stack. island.Clear(); int stackCount = 0; stack[stackCount++] = seed; seed.BodyFlags |= b2BodyFlags.e_islandFlag; // Perform a depth first search (DFS) on theraint graph. while (stackCount > 0) { // Grab the next body off the stack and add it to the island. b2Body b = stack[--stackCount]; island.Add(b); // Make sure the body is awake. b.SetAwake(true); // To keep islands as small as possible, we don't // propagate islands across static bodies. if (b.BodyType == b2BodyType.b2_staticBody) { continue; } // Search all contacts connected to this body. for (b2ContactEdge ce = b.ContactList; ce != null; ce = ce.next) { b2Contact contact = ce.contact; // Has this contact already been added to an island? if (contact.ContactFlags & b2ContactFlags.e_islandFlag) { continue; } // Is this contact solid and touching? if (contact.IsEnabled() == false || contact.IsTouching() == false) { continue; } // Skip sensors. bool sensorA = contact.m_fixtureA.m_isSensor; bool sensorB = contact.m_fixtureB.m_isSensor; if (sensorA || sensorB) { continue; } island.Add(contact); contact.ContactFlags |= b2ContactType.e_islandFlag; b2Body other = ce.other; // Was the other body already added to this island? if ((other.BodyFlags & b2BodyFlags.e_islandFlag) > 0) { continue; } stack[stackCount++] = other; other.BodyFlags |= b2BodyFlags.e_islandFlag; } // Search all joints connect to this body. for (b2JointEdge je = b.JointList; je; je = je.next) { if (je.joint.IslandFlag == true) { continue; } b2Body other = je.other; // Don't simulate joints connected to inactive bodies. if (other.IsActive() == false) { continue; } island.Add(je.joint); je.joint.m_islandFlag = true; if ((other.BodyFlags & b2BodyFlags.e_islandFlag) > 0) { continue; } stack[stackCount++] = other; other.BodyFlags |= b2BodyFlags.e_islandFlag; } } b2Profile profile = island.Solve(step, m_gravity, m_allowSleep); m_profile.solveInit += profile.solveInit; m_profile.solveVelocity += profile.solveVelocity; m_profile.solvePosition += profile.solvePosition; // Post solve cleanup. for (int i = 0; i < island.m_bodyCount; ++i) { // Allow static bodies to participate in other islands. b2Body b = island.m_bodies[i]; if (b.BodyType == b2BodyType.b2_staticBody) { b.BodyFlags &= ~b2BodyFlags.e_islandFlag; } } } { b2Timer timer; // Synchronize fixtures, check for out of range bodies. for (b2Body b = m_bodyList; b != null; b = b.Next) { // If a body was not in an island then it did not move. if ((b.BodyFlags & b2BodyType.e_islandFlag) == 0) { continue; } if (b.GetBodyType() == b2BodyType.b2_staticBody) { continue; } // Update fixtures (for broad-phase). b.SynchronizeFixtures(); } // Look for new contacts. m_contactManager.FindNewContacts(); m_profile.broadphase = timer.GetMilliseconds(); } }
public void DrawDebugData() { if (m_debugDraw == null) { return; } b2DrawFlags flags = m_debugDraw.GetFlags(); if (flags & b2DrawFlags.e_shapeBit) { for (b2Body b = m_bodyList; b; b = b.Next) { b2Transform xf = b.Transform; for (b2Fixture f = b.FixtureList; f != null; f = f.Next) { if (b.IsActive() == false) { DrawShape(f, xf, new b2Color(0.5f, 0.5f, 0.3f)); } else if (b.GetType() == b2BodyType.b2_staticBody) { DrawShape(f, xf, new b2Color(0.5f, 0.9f, 0.5f)); } else if (b.GetType() == b2BodyType.b2_kinematicBody) { DrawShape(f, xf, new b2Color(0.5f, 0.5f, 0.9f)); } else if (b.IsAwake() == false) { DrawShape(f, xf, new b2Color(0.6f, 0.6f, 0.6f)); } else { DrawShape(f, xf, new b2Color(0.9f, 0.7f, 0.7f)); } } } } if (flags.HasFlag(b2DrawFlags.e_jointBit)) { for (b2Joint j = m_jointList; j != null; j = j.GetNext()) { DrawJoint(j); } } if (flags.HasFlag(b2DrawFlags.e_pairBit)) { b2Color color = new b2Color(0.3f, 0.9f, 0.9f); for (b2Contact c = m_contactManager.ContactList; c != null; c = c.Next) { //b2Fixture fixtureA = c.GetFixtureA(); //b2Fixture fixtureB = c.GetFixtureB(); //b2Vec2 cA = fixtureA.GetAABB().GetCenter(); //b2Vec2 cB = fixtureB.GetAABB().GetCenter(); //m_debugDraw.DrawSegment(cA, cB, color); } } if (flags.HasFlag(b2DrawFlags.e_aabbBit)) { b2Color color(0.9f, 0.3f, 0.9f); b2BroadPhase bp = m_contactManager.BroadPhase; for (b2Body b = m_bodyList; b != null; b = b.Next) { if (b.IsActive() == false) { continue; } for (b2Fixture f = b.FixtureList; f != null; f = f.Next) { for (int i = 0; i < f.ProxyCount; ++i) { b2FixtureProxy proxy = f.Proxies[i]; b2AABB aabb = bp.GetFatAABB(proxy.proxyId); b2Vec2[] vs = new b2Vec2[4]; vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); m_debugDraw.DrawPolygon(vs, 4, color); } } } } if (flags.HasFlag(b2DrawFlags.e_centerOfMassBit)) { for (b2Body b = m_bodyList; b != null; b = b.Next) { b2Transform xf = b.Transform; xf.p = b.WorldCenter; m_debugDraw.DrawTransform(xf); } } }
// This is the top level collision call for the time step. Here // all the narrow phase collision is processed for the world // contact list. public void Collide() { // Update awake contacts. b2Contact c = m_contactList; while (c) { b2Fixture fixtureA = c.GetFixtureA(); b2Fixture fixtureB = c.GetFixtureB(); int indexA = c.GetChildIndexA(); int indexB = c.GetChildIndexB(); b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); // Is this contact flagged for filtering? if (c.m_flags & b2Contact.e_filterFlag) { // Should these bodies collide? if (bodyB.ShouldCollide(bodyA) == false) { b2Contact cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } // Check user filtering. if (m_contactFilter && m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { b2Contact cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } // Clear the filtering flag. c.m_flags &= ~b2Contact.e_filterFlag; } bool activeA = bodyA.IsAwake() && bodyA.m_type != b2BodyType.b2_staticBody; bool activeB = bodyB.IsAwake() && bodyB.m_type != b2BodyType.b2_staticBody; // At least one body must be awake and it must be dynamic or kinematic. if (activeA == false && activeB == false) { c = c.GetNext(); continue; } int proxyIdA = fixtureA.m_proxies[indexA].proxyId; int proxyIdB = fixtureB.m_proxies[indexB].proxyId; bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); // Here we destroy contacts that cease to overlap in the broad-phase. if (overlap == false) { b2Contact cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } // The contact persists. c.Update(m_contactListener); c = c.GetNext(); } }
public JObject B2n(b2Body body) { JObject bodyValue = new JObject(); string bodyName = GetBodyName(body); if (null != bodyName) bodyValue["name"] = bodyName; switch (body.BodyType) { case b2BodyType.b2_staticBody: bodyValue["type"] = 0; break; case b2BodyType.b2_kinematicBody: bodyValue["type"] = 1; break; case b2BodyType.b2_dynamicBody: bodyValue["type"] = 2; break; } VecToJson("position", body.Position, bodyValue); FloatToJson("angle", body.Angle, bodyValue); VecToJson("linearVelocity", body.LinearVelocity, bodyValue); FloatToJson("angularVelocity", body.AngularVelocity, bodyValue); if (body.LinearDamping != 0) FloatToJson("linearDamping", body.LinearDamping, bodyValue); if (body.AngularDamping != 0) FloatToJson("angularDamping", body.AngularDamping, bodyValue); if (body.GravityScale != 1) FloatToJson("gravityScale", body.GravityScale, bodyValue); if (body.IsBullet()) bodyValue["bullet"] = true; if (!body.IsSleepingAllowed()) bodyValue["allowSleep"] = false; if (body.IsAwake()) bodyValue["awake"] = true; if (!body.IsActive()) bodyValue["active"] = false; if (body.IsFixedRotation()) bodyValue["fixedRotation"] = true; b2MassData massData = new b2MassData(); massData = body.GetMassData(); if (massData.mass != 0) FloatToJson("massData-mass", massData.mass, bodyValue); if (massData.center.x != 0 || massData.center.y != 0) VecToJson("massData-center", body.LocalCenter, bodyValue); if (massData.I != 0) { FloatToJson("massData-I", massData.I, bodyValue); } //int i = 0; JArray arr = new JArray(); b2Body tmp = body; while (tmp != null) { bodyValue.Add("fixture", B2n(tmp)); tmp = body.Next; } bodyValue["fixture"] = arr; JArray customPropertyValue = WriteCustomPropertiesToJson(body); if (customPropertyValue.Count > 0) bodyValue["customProperties"] = customPropertyValue; return bodyValue; }
// This is the top level collision call for the time step. Here // all the narrow phase collision is processed for the world // contact list. public void Collide() { // Update awake contacts. b2Contact c = m_world.m_contactList; while (c != null) { b2Fixture fixtureA = c.GetFixtureA(); b2Fixture fixtureB = c.GetFixtureB(); b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); if (bodyA.IsAwake() == false && bodyB.IsAwake() == false) { c = c.GetNext(); continue; } b2Contact cNuke; // Is this contact flagged for filtering? if ((c.m_flags & b2Contact.e_filterFlag) > 0) { // Should these bodies collide? if (bodyB.ShouldCollide(bodyA) == false) { cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } // Check user filtering. if (m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } // Clear the filtering flag c.m_flags &= ~b2Contact.e_filterFlag; } object proxyA = fixtureA.m_proxy; object proxyB = fixtureB.m_proxy; bool overlap = m_broadPhase.TestOverlap(proxyA, proxyB); // Here we destroy contacts that cease to overlap in the broadphase if (overlap == false) { cNuke = c; c = cNuke.GetNext(); Destroy(cNuke); continue; } c.Update(m_contactListener); c = c.GetNext(); } }