public void Destroy(b2Contact contact) { if (contact.m_manifold.m_pointCount > 0) { contact.m_fixtureA.m_body.SetAwake(true); contact.m_fixtureB.m_body.SetAwake(true); } int type1 = contact.m_fixtureA.GetType(); int type2 = contact.m_fixtureB.GetType(); //b2Settings.b2Assert(b2Shape.e_unknownShape < type1 && type1 < b2Shape.e_shapeTypeCount); //b2Settings.b2Assert(b2Shape.e_unknownShape < type2 && type2 < b2Shape.e_shapeTypeCount); b2ContactRegister reg = m_registers[type1][type2]; if (true) { reg.poolCount++; contact.m_next = reg.pool; reg.pool = contact; } Action <b2Contact, object> destroyFcn = reg.destroyFcn; destroyFcn(contact, m_allocator); }
public b2ContactManager() { m_contactList = null; m_contactCount = 0; m_contactFilter = b2ContactFilter.b2_defaultFilter; m_contactListener = b2ContactListener.b2_defaultListener; m_broadPhase = new b2BroadPhase(); }
public override void PostSolve(b2Contact contact, ref b2ContactImpulse impulse) { if (m_broke) { // The body already broke. return; } // Should the body break? int count = contact.GetManifold().pointCount; float maxImpulse = 0.0f; for (int i = 0; i < count; ++i) { maxImpulse = Math.Max(maxImpulse, impulse.normalImpulses[i]); } if (maxImpulse > 40.0f) { // Flag the body for breaking. m_break = true; } }
// Implement contact listener. public override void BeginContact(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] = true; } } if (fixtureB == m_sensor) { object userData = fixtureA.Body.UserData; if (userData != null) { m_touching[(int)userData] = true; } } }
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); } }
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 PostSolve(b2Contact contact, ref b2ContactImpulse impulse) { }
// http://www.box2dflash.org/docs/2.1a/reference/Box2D/Dynamics/b2ContactListener.html public void BeginContact(b2Contact contact) { }
public void EndContact(b2Contact contact) { }
public override void PostSolve(b2Contact contact, ref b2ContactImpulse impulse) { //throw new NotImplementedException (); }
/// <summary> /// This is called after a contact is updated. This allows you to inspect a /// contact before it goes to the solver. If you are careful, you can modify the /// contact manifold (e.g. disable contact). /// A copy of the old manifold is provided so that you can detect changes. /// Note: this is called only for awake bodies. /// Note: this is called even when the number of contact points is zero. /// Note: this is not called for sensors. /// Note: if you set the number of contact points to zero, you will not /// get an EndContact callback. However, you may get a BeginContact callback /// the next step. /// </summary> public abstract void PreSolve(b2Contact contact, b2Manifold oldManifold);
public void Destroy(b2Contact c) { b2Fixture fixtureA = c.FixtureA; b2Fixture fixtureB = c.FixtureB; b2Body bodyA = fixtureA.Body; b2Body bodyB = fixtureB.Body; if (m_contactListener != null && c.IsTouching()) { m_contactListener.EndContact(c); } // Remove from the world. if (c.Prev != null) { c.Prev.Next = c.Next; } if (c.Next != null) { c.Next.Prev = c.Prev; } if (c == m_contactList) { m_contactList = c.Next; } // Remove from body 1 if (c.NodeA.Prev != null) { c.NodeA.Prev.Next = c.NodeA.Next; } if (c.NodeA.Next != null) { c.NodeA.Next.Prev = c.NodeA.Prev; } if (c.NodeA == bodyA.ContactList) { bodyA.ContactList = c.NodeA.Next; } // Remove from body 2 if (c.NodeB.Prev != null) { c.NodeB.Prev.Next = c.NodeB.Next; } if (c.NodeB.Next != null) { c.NodeB.Next.Prev = c.NodeB.Prev; } if (c.NodeB == bodyB.ContactList) { bodyB.ContactList = c.NodeB.Next; } // Call the factory. --m_contactCount; }
public b2ContactSolver(b2ContactSolverDef def) { m_step = def.step; m_count = def.count; m_positionConstraints = new b2ContactPositionConstraint[m_count]; for (int pc = 0; pc < m_count; pc++) { m_positionConstraints[pc] = b2ContactPositionConstraint.Create(); } m_velocityConstraints = new b2ContactVelocityConstraint[m_count]; for (int vc = 0; vc < m_count; vc++) { m_velocityConstraints[vc] = b2ContactVelocityConstraint.Create(); } m_positions = def.positions; m_velocities = def.velocities; m_contacts = def.contacts; // Initialize position independent portions of the constraints. for (int i = 0; i < m_count; ++i) { b2Contact contact = m_contacts[i]; b2Fixture fixtureA = contact.FixtureA; b2Fixture fixtureB = contact.FixtureB; b2Shape shapeA = fixtureA.Shape; b2Shape shapeB = fixtureB.Shape; float radiusA = shapeA.Radius; float radiusB = shapeB.Radius; b2Body bodyA = fixtureA.Body; b2Body bodyB = fixtureB.Body; b2Manifold manifold = contact.GetManifold(); int pointCount = manifold.pointCount; Debug.Assert(pointCount > 0); b2ContactVelocityConstraint vc = m_velocityConstraints[i]; vc.friction = contact.Friction; vc.restitution = contact.Restitution; vc.indexA = bodyA.IslandIndex; vc.indexB = bodyB.IslandIndex; vc.invMassA = bodyA.InvertedMass; vc.invMassB = bodyB.InvertedMass; vc.invIA = bodyA.InvertedI; vc.invIB = bodyB.InvertedI; vc.contactIndex = i; vc.pointCount = pointCount; vc.K.SetZero(); vc.normalMass.SetZero(); b2ContactPositionConstraint pc = m_positionConstraints[i]; pc.indexA = bodyA.IslandIndex; pc.indexB = bodyB.IslandIndex; pc.invMassA = bodyA.InvertedMass; pc.invMassB = bodyB.InvertedMass; pc.localCenterA = bodyA.Sweep.localCenter; pc.localCenterB = bodyB.Sweep.localCenter; pc.invIA = bodyA.InvertedI; pc.invIB = bodyB.InvertedI; pc.localNormal = manifold.localNormal; pc.localPoint = manifold.localPoint; pc.pointCount = pointCount; pc.radiusA = radiusA; pc.radiusB = radiusB; pc.type = manifold.type; for (int j = 0; j < pointCount; ++j) { b2ManifoldPoint cp = manifold.points[j]; b2VelocityConstraintPoint vcp = vc.points[j]; if (m_step.warmStarting) { vcp.normalImpulse = m_step.dtRatio * cp.normalImpulse; vcp.tangentImpulse = m_step.dtRatio * cp.tangentImpulse; } else { vcp.normalImpulse = 0.0f; vcp.tangentImpulse = 0.0f; } vcp.rA.SetZero(); vcp.rB.SetZero(); vcp.normalMass = 0.0f; vcp.tangentMass = 0.0f; vcp.velocityBias = 0.0f; pc.localPoints[j] = cp.localPoint; //vc.points[j] = vcp; } //Put back the struct data since struct data is copied by value //m_positionConstraints[i] = pc; //m_velocityConstraints[i] = vc; } }
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 override void BeginContact(b2Contact contact) { base.BeginContact(contact); PlanetCuteRubeLayer layer = m_layer; b2Fixture fA = contact.GetFixtureA(); b2Fixture fB = contact.GetFixtureB(); if (fA == layer.m_footSensorFixture || fB == layer.m_footSensorFixture) layer.m_numFootContacts++; //CCLOG("Num foot contacts: %d", layer->m_numFootContacts); PlanetCuteFixtureUserData fudA = (PlanetCuteFixtureUserData)fA.UserData; PlanetCuteFixtureUserData fudB = (PlanetCuteFixtureUserData)fB.UserData; if (fudA.fixtureType == _fixtureType.FT_PICKUP && fB.Body == layer.m_playerBody) layer.m_pickupsToProcess.Add(fudA); if (fudB.fixtureType == _fixtureType.FT_PICKUP && fA.Body == layer.m_playerBody) layer.m_pickupsToProcess.Add(fudB); }
static public void Destroy(b2Contact contact, object allocator) { //((b2PolyContact*)contact)->~b2PolyContact(); //allocator->Free(contact, sizeof(b2PolyContact)); }
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 override void PreSolve(b2Contact contact, ref b2Manifold oldManifold) { //throw new NotImplementedException (); }
public override void BeginContact(b2Contact contact) {}
static public void Destroy(b2Contact contact, object allocator) { // }
public override void EndContact(b2Contact contact) {}
/// <summary> /// Called when two fixtures begin to touch. /// </summary> public virtual void BeginContact(b2Contact contact) { }
// called by Box2D during the Step function when two fixtures finish touching public override void EndContact(b2Contact contact) { base.EndContact(contact); PlanetCuteRubeLayer layer = (PlanetCuteRubeLayer)m_layer; b2Fixture fA = contact.GetFixtureA(); b2Fixture fB = contact.GetFixtureB(); if (fA == layer.m_footSensorFixture || fB == layer.m_footSensorFixture) layer.m_numFootContacts--; //CCLOG("Num foot contacts: %d", layer->m_numFootContacts); }
public override void EndContact(b2Contact contact) { base.EndContact (contact); }
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.Body; b2Body bodyB = fixtureB.Body; // 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.ContactList; while (edge != null) { 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)) { return; } // Check user filtering. if (m_contactFilter != null && !m_contactFilter.ShouldCollide(fixtureA, fixtureB)) { return; } // Call the factory. b2Contact c = b2Contact.Create(fixtureA, indexA, fixtureB, indexB); if (c == null) { return; } // Contact creation may swap fixtures. fixtureA = c.GetFixtureA(); fixtureB = c.GetFixtureB(); indexA = c.GetChildIndexA(); indexB = c.GetChildIndexB(); bodyA = fixtureA.Body; bodyB = fixtureB.Body; // Insert into the world. c.Prev = null; c.Next = m_contactList; if (m_contactList != null) { m_contactList.Prev = c; } m_contactList = c; // Connect to island graph. // Connect to body A c.NodeA.Contact = c; c.NodeA.Other = bodyB; c.NodeA.Prev = null; c.NodeA.Next = bodyA.ContactList; if (bodyA.ContactList != null) { bodyA.ContactList.Prev = c.NodeA; } bodyA.ContactList = c.NodeA; // Connect to body B c.NodeB.Contact = c; c.NodeB.Other = bodyA; c.NodeB.Prev = null; c.NodeB.Next = bodyB.ContactList; if (bodyB.ContactList != null) { bodyB.ContactList.Prev = c.NodeB; } bodyB.ContactList = c.NodeB; // Wake up the bodies bodyA.SetAwake(true); bodyB.SetAwake(true); ++m_contactCount; }
public override void PreSolve(b2Contact contact, Box2D.Collision.b2Manifold oldManifold) { }
public void Add(b2Contact contact) { Debug.Assert(m_contactCount < m_contactCapacity); m_contacts[m_contactCount++] = contact; }
public override void PostSolve(Box2D.Dynamics.Contacts.b2Contact contact, ref b2ContactImpulse impulse) { }
/// <summary> /// Called when two fixtures cease to touch. /// </summary> public virtual void EndContact(b2Contact contact) { }
public override void PreSolve(b2Contact contact, b2Manifold oldManifold) { }
/// <summary> /// This lets you inspect a contact after the solver is finished. This is useful /// for inspecting impulses. /// Note: the contact manifold does not include time of impact impulses, which can be /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly /// in a separate data structure. /// Note: this is only called for contacts that are touching, solid, and awake. /// </summary> public abstract void PostSolve(b2Contact contact, ref b2ContactImpulse impulse);
public void PreSolve(b2Contact contact, b2Manifold oldManifold) { }