public override void BeginContact(b2Contact contact) { if (Env.hull == contact.GetFixtureA().GetBody() || Env.hull == contact.GetFixtureB().GetBody()) { Env.game_over = true; } foreach (var leg in new[] { Env.legs[1], Env.legs[3] }) { if (leg == contact.GetFixtureA().GetBody() || leg == contact.GetFixtureB().GetBody()) { (leg.GetUserData() as CustomBodyData).GroundContact = true; } } }
private CollisionDataNative GetCollisionData(b2Contact contact) { int colliderAId = contact.GetFixtureA().GetUserData().data; int colliderBId = contact.GetFixtureB().GetUserData().data; int physicsObjectAId = contact.GetFixtureA().GetBody().GetUserData().data; int physicsObjectBId = contact.GetFixtureB().GetBody().GetUserData().data; int childIndexA = contact.GetChildIndexA(); int childIndexB = contact.GetChildIndexB(); IPhysicsObject physicsObjectA = _Physics2D.GetPhysicsObject(physicsObjectAId); ICollider colliderA = physicsObjectA.GetCollider(colliderAId); IPhysicsObject physicsObjectB = _Physics2D.GetPhysicsObject(physicsObjectBId); ICollider colliderB = physicsObjectB.GetCollider(colliderBId); return(new CollisionDataNative(contact, physicsObjectA, colliderA, childIndexA, physicsObjectB, colliderB, childIndexB)); }
/** * Set if this fixture is a sensor. */ public void SetSensor(bool sensor) { if (m_isSensor == sensor) { return; } m_isSensor = sensor; if (m_body == null) { return; } b2ContactEdge edge = m_body.GetContactList(); while (edge != null) { b2Contact contact = edge.contact; b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); if (fixtureA == this || fixtureB == this) { contact.SetSensor(fixtureA.IsSensor() || fixtureB.IsSensor()); } edge = edge.next; } }
public override void PreSolve(b2Contact contact, b2Manifold oldManifold) { b2Manifold manifold = contact.GetManifold(); if (manifold.pointCount == 0) { return; } b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); b2Collision.b2GetPointStates(state1, state2, oldManifold, manifold); contact.GetWorldManifold(ref worldManifold); for (int i = 0; i < manifold.pointCount && m_pointCount < k_maxContactPoints; ++i) { ContactPoint cp = m_points[m_pointCount]; if (cp == null) { cp = new ContactPoint(); m_points[m_pointCount] = cp; } cp.fixtureA = fixtureA; cp.fixtureB = fixtureB; cp.position = worldManifold.points[i]; cp.normal = worldManifold.normal; cp.state = state2[i]; ++m_pointCount; } }
public override void EndContact(b2Contact contact) { foreach (var leg in new[] { Env.legs[1], Env.legs[3] }) { if (leg == contact.GetFixtureA().GetBody() || leg == contact.GetFixtureB().GetBody()) { (leg.GetUserData() as CustomBodyData).GroundContact = false; } } }
public override void BeginContact(b2Contact contact) { base.BeginContact(contact); b2Body bodyA = contact.GetFixtureA().Body; b2Body bodyB = contact.GetFixtureB().Body; if (((bodyA == Ball) || (bodyB == Ball)) && ((bodyA == Floor) || (bodyB == Floor))) { _layer.RequestStopGame(); } }
public virtual void Refilter() { if (m_body == null) { return; } // Flag associated contacts for filtering. b2ContactEdge edge = m_body.ContactList; while (edge != null) { b2Contact contact = edge.Contact; b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); if (fixtureA == this || fixtureB == this) { contact.FlagForFiltering(); } edge = edge.Next; } b2World world = m_body.World; if (world == null) { return; } // Touch each proxy so that new pairs may be created b2BroadPhase broadPhase = world.ContactManager.BroadPhase; for (int i = 0; i < m_proxyCount; ++i) { broadPhase.TouchProxy(m_proxies[i].proxyId); } }
// Implement contact listener. public override void EndContact(b2Contact contact) { b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); if (fixtureA == m_sensor) { object userData = fixtureB.Body.UserData; if (userData != null) { m_touching[(int)userData] = false; } } if (fixtureB == m_sensor) { object userData = fixtureA.Body.UserData; if (userData != null) { m_touching[(int)userData] = false; } } }
/** * Set the contact filtering data. This will not update contacts until the next time * step when either parent body is active and awake. */ public void SetFilterData(b2FilterData filter) { m_filter = filter.Copy(); if (m_body != null) { return; } b2ContactEdge edge = m_body.GetContactList(); while (edge != null) { b2Contact contact = edge.contact; b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); if (fixtureA == this || fixtureB == this) { contact.FlagForFiltering(); } edge = edge.next; } }
public override void PreSolve(b2Contact contact, b2Manifold oldManifold) { base.PreSolve(contact, oldManifold); b2Fixture fixtureA = contact.GetFixtureA(); b2Fixture fixtureB = contact.GetFixtureB(); if (fixtureA != m_platform && fixtureA != m_character) { return; } if (fixtureB != m_platform && fixtureB != m_character) { return; } b2Vec2 position = m_character.Body.Position; if (position.y < m_top + m_radius - 3.0f * b2Settings.b2_linearSlop) { contact.SetEnabled(false); } }
// 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(); } }
public void Destroy(b2Contact c) { b2Fixture fixtureA = c.GetFixtureA(); b2Fixture fixtureB = c.GetFixtureB(); b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); if (m_contactListener && c.IsTouching()) { m_contactListener.EndContact(c); } // Remove from the world. if (c.m_prev) { c.m_prev.m_next = c.m_next; } if (c.m_next) { c.m_next.m_prev = c.m_prev; } if (c == m_contactList) { m_contactList = c.m_next; } // Remove from body 1 if (c.m_nodeA.prev) { c.m_nodeA.prev.next = c.m_nodeA.next; } if (c.m_nodeA.next) { c.m_nodeA.next.prev = c.m_nodeA.prev; } if (c.m_nodeA == bodyA.m_contactList) { bodyA.m_contactList = c.m_nodeA.next; } // Remove from body 2 if (c.m_nodeB.prev) { c.m_nodeB.prev.next = c.m_nodeB.next; } if (c.m_nodeB.next) { c.m_nodeB.next.prev = c.m_nodeB.prev; } if (c.m_nodeB == bodyB.m_contactList) { bodyB.m_contactList = c.m_nodeB.next; } // Call the factory. b2Contact.Destroy(c); --m_contactCount; }
public void AddPair(object proxyUserDataA, object proxyUserDataB) { b2FixtureProxy proxyA = (b2FixtureProxy)proxyUserDataA; b2FixtureProxy proxyB = (b2FixtureProxy)proxyUserDataB; b2Fixture fixtureA = proxyA.fixture; b2Fixture fixtureB = proxyB.fixture; int indexA = proxyA.childIndex; int indexB = proxyB.childIndex; b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); // 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? b2ContactEdge edge = bodyB.GetContactList(); while (edge) { if (edge.other == bodyA) { b2Fixture fA = edge.contact.GetFixtureA(); b2Fixture 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 && m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { return; } // Call the factory. b2Contact c = b2Contact.Create(fixtureA, indexA, fixtureB, indexB, m_allocator); 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; // Wake up the bodies bodyA.SetAwake(true); bodyB.SetAwake(true); ++m_contactCount; }
// 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 override void BeginContact(b2Contact contact) { //base.BeginContact (contact); b2Body bodyA = contact.GetFixtureA().Body; b2Body bodyB = contact.GetFixtureB().Body; BodyNode bodyNodeA = (BodyNode)bodyA.UserData; BodyNode bodyNodeB = (BodyNode)bodyB.UserData; //////////////////////////////////////// //////////////////////////////////////// //NINJA NODES WITH GROUNDPLANE if (bodyNodeA is Ninja && bodyNodeB is GroundPlane) { Ninja theNinja = (Ninja)bodyNodeA; //GroundPlane* theGroundPlane = (GroundPlane*)bodyNodeB; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaOnGround(theNinja); TheLevel.SharedLevel.ProceedToNextTurn(theNinja); } else if (bodyNodeA is GroundPlane && bodyNodeB is Ninja) { Ninja theNinja = (Ninja)bodyNodeB; // GroundPlane* theGroundPlane = (GroundPlane*)bodyNodeA; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaOnGround(theNinja); TheLevel.SharedLevel.ProceedToNextTurn(theNinja); } //////////////////////////////////////// //////////////////////////////////////// //NINJA NODES WITH StackObject if (bodyNodeA is Ninja && bodyNodeB is StackObject) { //[[GameSounds sharedGameSounds] playStackImpactSound]; Ninja theNinja = (Ninja)bodyNodeA; StackObject theStackObject = (StackObject)bodyNodeB; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaImpactingStack(theNinja); theStackObject.PlayBreakAnimationFromNinjaContact(); if (theStackObject.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theStackObject.PointValue, theStackObject.Position, theStackObject.SimpleScoreVisualFX); //show points theStackObject.MakeUnScoreable(); //prevents scoring off same object twice } } else if (bodyNodeA is StackObject && bodyNodeB is Ninja) { //[[GameSounds sharedGameSounds] playStackImpactSound]; Ninja theNinja = (Ninja)bodyNodeB; StackObject theStackObject = (StackObject)bodyNodeA; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaImpactingStack(theNinja); theStackObject.PlayBreakAnimationFromNinjaContact(); if (theStackObject.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theStackObject.PointValue, theStackObject.Position, theStackObject.SimpleScoreVisualFX); //show points theStackObject.MakeUnScoreable(); //prevents scoring off same object twice } } //////////////////////////////////////// //////////////////////////////////////// //NINJA NODES WITH Enemy if (bodyNodeA is Ninja && bodyNodeB is Enemy) { Ninja theNinja = (Ninja)bodyNodeA; Enemy theEnemy = (Enemy)bodyNodeB; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaImpactingStack(theNinja); //applies to stack objects or enemies if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } else if (bodyNodeA is Enemy && bodyNodeB is Ninja) { Ninja theNinja = (Ninja)bodyNodeB; Enemy theEnemy = (Enemy)bodyNodeA; TheLevel.SharedLevel.StopDotting(); TheLevel.SharedLevel.ShowNinjaImpactingStack(theNinja); //applies to stack objects or enemies if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } //////////////////////////////////////// //////////////////////////////////////// //StackObject WITH Enemy if (bodyNodeA is StackObject && bodyNodeB is Enemy) { StackObject theStackObject = (StackObject)bodyNodeA; Enemy theEnemy = (Enemy)bodyNodeB; if (theStackObject.IsCanDamageEnemy && theEnemy.DamagesFromDamageEnabledStackObjects) { if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } } else if (bodyNodeA is Enemy && bodyNodeB is StackObject) { StackObject theStackObject = (StackObject)bodyNodeB; Enemy theEnemy = (Enemy)bodyNodeA; if (theStackObject.IsCanDamageEnemy && theEnemy.DamagesFromDamageEnabledStackObjects) { if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } } //////////////////////////////////////// //////////////////////////////////////// //Ground WITH Enemy if (bodyNodeA is GroundPlane && bodyNodeB is Enemy) { Enemy theEnemy = (Enemy)bodyNodeB; if (theEnemy.DamagesFromGroundContact) { if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } } else if (bodyNodeA is Enemy && bodyNodeB is GroundPlane) { Enemy theEnemy = (Enemy)bodyNodeA; if (theEnemy.DamagesFromGroundContact) { if (theEnemy.BreaksOnNextDamage) { if (theEnemy.PointValue != 0) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theEnemy.PointValue, theEnemy.Position, theEnemy.SimpleScoreVisualFX); //show points theEnemy.MakeUnScoreable(); //prevents scoring off same object twice } theEnemy.BreakEnemy(); } else { theEnemy.DamageEnemy(); } } } //////////////////////////////////////// //////////////////////////////////////// //Ground WITH StackObject if (bodyNodeA is GroundPlane && bodyNodeB is StackObject) { StackObject theStackObject = (StackObject)bodyNodeB; theStackObject.PlayBreakAnimationFromGroundContact(); if (theStackObject.PointValue != 0 && theStackObject.IsBreaksOnGroundContact) { // if it has a score value for impact with Ninja TheLevel.SharedLevel.ShowPoints(theStackObject.PointValue, theStackObject.Position, theStackObject.SimpleScoreVisualFX); //show points theStackObject.MakeUnScoreable(); //prevents scoring off same object twice } } else if (bodyNodeA is StackObject && bodyNodeB is GroundPlane) { StackObject theStackObject = (StackObject)bodyNodeA; theStackObject.PlayBreakAnimationFromGroundContact(); if (theStackObject.PointValue != 0 && theStackObject.IsBreaksOnGroundContact) // if it has a score value for impact with Ninja { TheLevel.SharedLevel.ShowPoints(theStackObject.PointValue, theStackObject.Position, theStackObject.SimpleScoreVisualFX); //show points theStackObject.MakeUnScoreable(); //prevents scoring off same object twice } } }
public void SolveTOI(b2TimeStep subStep, int toiIndexA, int toiIndexB) { Debug.Assert(toiIndexA < m_bodyCount); Debug.Assert(toiIndexB < m_bodyCount); // Initialize the body state. for (int i = 0; i < m_bodyCount; ++i) { b2Body b = m_bodies[i]; m_positions[i].c = b.Sweep.c; m_positions[i].a = b.Sweep.a; m_velocities[i].v = b.LinearVelocity; m_velocities[i].w = b.AngularVelocity; } b2ContactSolverDef contactSolverDef; contactSolverDef.contacts = m_contacts; contactSolverDef.count = m_contactCount; contactSolverDef.step = subStep; contactSolverDef.positions = m_positions; contactSolverDef.velocities = m_velocities; b2ContactSolver contactSolver = new b2ContactSolver(contactSolverDef); // Solve position constraints. for (int i = 0; i < subStep.positionIterations; ++i) { bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); if (contactsOkay) { break; } } #if false // Is the new position really safe? for (int i = 0; i < m_contactCount; ++i) { b2Contact c = m_contacts[i]; b2Fixture fA = c.GetFixtureA(); b2Fixture fB = c.GetFixtureB(); b2Body bA = fA.Body; b2Body bB = fB.Body; int indexA = c.GetChildIndexA(); int indexB = c.GetChildIndexB(); b2DistanceInput input = new b2DistanceInput(); input.proxyA.Set(fA.Shape, indexA); input.proxyB.Set(fB.Shape, indexB); input.transformA = bA.Transform; input.transformB = bB.Transform; input.useRadii = false; b2DistanceOutput output; b2SimplexCache cache = new b2SimplexCache(); cache.count = 0; output = b2Distance(cache, input); if (output.distance == 0 || cache.count == 3) { cache.count += 0; } } #endif // Leap of faith to new safe state. m_bodies[toiIndexA].Sweep.c0 = m_positions[toiIndexA].c; m_bodies[toiIndexA].Sweep.a0 = m_positions[toiIndexA].a; m_bodies[toiIndexB].Sweep.c0 = m_positions[toiIndexB].c; m_bodies[toiIndexB].Sweep.a0 = m_positions[toiIndexB].a; // No warm starting is needed for TOI events because warm // starting impulses were applied in the discrete solver. contactSolver.InitializeVelocityConstraints(); // Solve velocity constraints. for (int i = 0; i < subStep.velocityIterations; ++i) { contactSolver.SolveVelocityConstraints(); } // Don't store the TOI contact forces for warm starting // because they can be quite large. float h = subStep.dt; // Integrate positions for (int i = 0; i < m_bodyCount; ++i) { b2Vec2 c = m_positions[i].c; float a = m_positions[i].a; b2Vec2 v = m_velocities[i].v; float w = m_velocities[i].w; // Check for large velocities b2Vec2 translation = h * v; if (b2Math.b2Dot(translation, translation) > b2Settings.b2_maxTranslationSquared) { float ratio = b2Settings.b2_maxTranslation / translation.Length; v *= ratio; } float rotation = h * w; if (rotation * rotation > b2Settings.b2_maxRotationSquared) { float ratio = b2Settings.b2_maxRotation / Math.Abs(rotation); w *= ratio; } // Integrate c += h * v; a += h * w; m_positions[i].c = c; m_positions[i].a = a; m_velocities[i].v = v; m_velocities[i].w = w; // Sync bodies b2Body body = m_bodies[i]; body.Sweep.c = c; body.Sweep.a = a; body.LinearVelocity = v; body.AngularVelocity = w; body.SynchronizeTransform(); } Report(contactSolver.m_velocityConstraints); }
public void PostSolve(b2Contact contact, b2ContactImpulse impulse) { // http://stackoverflow.com/questions/11149091/box2d-damage-physics //M:\web\FlashHeatZeekerWithStarlingB2\XContactListener.as(34): col: 83 Error: Implicit coercion of a value of type __AS3__.vec:Vector.<Number> to an unrelated type __AS3__.vec:Vector.<*>. //double0 = __Enumerable.Sum_100669321(X.AsEnumerable_100664676(impulse.normalImpulses)); // http://blog.allanbishop.com/box-2d-2-1a-tutorial-part-6-collision-strength/ var forceA = impulse.normalImpulses[0]; // { impulse = { length = 2, forceA = 2.9642496469208197, forceB = 0 } } var forceB = impulse.normalImpulses[1]; if (DiscardSmallImpulse) { if (forceA < 0.5) { if (forceB < 0.5) { // do we care about friction? return; } } } //var min = impulse.normalImpulses.AsEnumerable().Min(); //var max = impulse.normalImpulses.AsEnumerable().Max(); // System.Linq.Enumerable for Double Min(System.Collections.Generic.IEnumerable`1[System.Double]) used at //FlashHeatZeekerWithStarlingB2.XContactListener.PostSolve at offset 001d. var done = false; var fixA = contact.GetFixtureA(); if (fixA != null) { var hitA = fixA.GetUserData() as Action <double>; if (hitA != null) { //Console.WriteLine(new //{ // hitA = new // { // forceA, // } //}); hitA(forceA); done = true; } } var fixB = contact.GetFixtureB(); if (fixB != null) { var hitB = fixB.GetUserData() as Action <double>; if (hitB != null) { //Console.WriteLine(new //{ // hitB = new // { // forceA, // } //}); hitB(forceA); done = true; } } if (done) { return; } Console.WriteLine(new { impulse = new { impulse.normalImpulses.length, forceA, fixA, forceB, fixB //, min, max } }); }
public void Destroy(b2Contact c) { b2Fixture fixtureA = c.GetFixtureA(); b2Fixture fixtureB = c.GetFixtureB(); b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); if (m_contactListener && c.IsTouching()) { m_contactListener.EndContact(c); } // Remove from the world. if (c.m_prev) { c.m_prev.m_next = c.m_next; } if (c.m_next) { c.m_next.m_prev = c.m_prev; } if (c == m_contactList) { m_contactList = c.m_next; } // Remove from body 1 if (c.m_nodeA.prev) { c.m_nodeA.prev.next = c.m_nodeA.next; } if (c.m_nodeA.next) { c.m_nodeA.next.prev = c.m_nodeA.prev; } if (c.m_nodeA == bodyA.m_contactList) { bodyA.m_contactList = c.m_nodeA.next; } // Remove from body 2 if (c.m_nodeB.prev) { c.m_nodeB.prev.next = c.m_nodeB.next; } if (c.m_nodeB.next) { c.m_nodeB.next.prev = c.m_nodeB.prev; } if (c.m_nodeB == bodyB.m_contactList) { bodyB.m_contactList = c.m_nodeB.next; } // Call the factory. b2Contact.Destroy(c); --m_contactCount; }
/// 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(b2Fixture fixture) { if (fixture == null) { return; } Debug.Assert(m_world.IsLocked() == false); if (m_world.IsLocked() == true) { return; } Debug.Assert(fixture.m_body == this); // Remove the fixture from this body's singly linked list. Debug.Assert(m_fixtureCount > 0); b2Fixture node = m_fixtureList; bool found = false; while (node != null) { if (node == fixture) { node = fixture.m_next; found = true; break; } node = node.m_next; } // You tried to remove a shape that is not attached to this body. Debug.Assert(found); // Destroy any contacts associated with the fixture. b2ContactEdge edge = m_contactList; while (edge != null) { b2Contact c = edge.contact; edge = edge.next; b2Fixture fixtureA = c.GetFixtureA(); b2Fixture 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 & BodyFlags.e_activeFlag) != 0) { b2BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase; fixture.DestroyProxies(broadPhase); } fixture.m_body = null; fixture.m_next = null; fixture.Destroy(); --m_fixtureCount; // Reset the mass data. ResetMassData(); }
// 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; } } } }
// This is a callback from the broadphase when two AABB proxies begin // to overlap. We create a b2Contact to manage the narrow phase. public void AddPair(object proxyUserDataA, object proxyUserDataB) { b2Fixture fixtureA = proxyUserDataA as b2Fixture; b2Fixture fixtureB = proxyUserDataB as b2Fixture; b2Body bodyA = fixtureA.GetBody(); b2Body bodyB = fixtureB.GetBody(); // Are the fixtures on the same body? if (bodyA == bodyB) { return; } // Does a contact already exist? b2ContactEdge edge = bodyB.GetContactList(); while (edge != null) { if (edge.other == bodyA) { b2Fixture fA = edge.contact.GetFixtureA(); b2Fixture fB = edge.contact.GetFixtureB(); if (fA == fixtureA && fB == fixtureB) { return; } if (fA == fixtureB && fB == fixtureA) { 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.ShouldCollide(fixtureA, fixtureB) == false) { return; } // Call the factory. b2Contact c = m_contactFactory.Create(fixtureA, fixtureB); // Contact creation may swap shapes. fixtureA = c.GetFixtureA(); fixtureB = c.GetFixtureB(); bodyA = fixtureA.m_body; bodyB = fixtureB.m_body; // Insert into the world. c.m_prev = null; c.m_next = m_world.m_contactList; if (m_world.m_contactList != null) { m_world.m_contactList.m_prev = c; } m_world.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 2 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_world.m_contactCount; return; }