The Contact manager works together with the contact factory.
Comment
(web)
world instantiate contactmanager
b2World.b2World = function () {
this.s_stack = new Vector();
this.m_contactManager = new b2ContactManager();
this.m_contactSolver = new b2ContactSolver();
this.m_island = new b2Island();
};
b2World.prototype.b2World = function (gravity, doSleep) {
this.m_destructionListener = null;
this.m_debugDraw = null;
this.m_bodyList = null;
this.m_contactList = null;
this.m_jointList = null;
this.m_controllerList = null;
this.m_bodyCount = 0;
this.m_contactCount = 0;
this.m_jointCount = 0;
this.m_controllerCount = 0;
b2World.m_warmStarting = true;
b2World.m_continuousPhysics = true;
this.m_allowSleep = doSleep;
this.m_gravity = gravity;
this.m_inv_dt0 = 0.0;
this.m_contactManager.m_world = this;
var bd = new b2BodyDef();
this.m_groundBody = this.CreateBody(bd);
}
b2World.prototype.Validate = function () {
this.m_contactManager.m_broadPhase.Validate();
}
world.step
b2World.prototype.Step = function (dt, velocityIterations, positionIterations) {
if (dt === undefined) dt = 0;
if (velocityIterations === undefined) velocityIterations = 0;
if (positionIterations === undefined) positionIterations = 0;
if (this.m_flags & b2World.e_newFixture) {
this.m_contactManager.FindNewContacts();
this.m_flags &= ~b2World.e_newFixture;
}
this.m_flags |= b2World.e_locked;
var step = b2World.s_timestep2;
step.dt = dt;
step.velocityIterations = velocityIterations;
step.positionIterations = positionIterations;
if (dt > 0.0) {
step.inv_dt = 1.0 / dt;
}
else {
step.inv_dt = 0.0;
}
step.dtRatio = this.m_inv_dt0 * dt;
step.warmStarting = b2World.m_warmStarting;
this.m_contactManager.Collide();
if (step.dt > 0.0) {
this.Solve(step);
}
if (b2World.m_continuousPhysics && step.dt > 0.0) {
this.SolveTOI(step);
}
if (step.dt > 0.0) {
this.m_inv_dt0 = step.inv_dt;
}
this.m_flags &= ~b2World.e_locked;
}
and from island
b2World.prototype.Solve = function (step) {
var b;
for (var controller = this.m_controllerList; controller; controller = controller.m_next) {
controller.Step(step);
}
var island = this.m_island;
island.Initialize(this.m_bodyCount, this.m_contactCount, this.m_jointCount, null, this.m_contactManager.m_contactListener, this.m_contactSolver);
for (b = this.m_bodyList;
b; b = b.m_next) {
b.m_flags &= ~b2Body.e_islandFlag;
}
for (var c = this.m_contactList; c; c = c.m_next) {
c.m_flags &= ~b2Contact.e_islandFlag;
}
for (var j = this.m_jointList; j; j = j.m_next) {
j.m_islandFlag = false;
}
var stackSize = parseInt(this.m_bodyCount);
var stack = this.s_stack;
for (var seed = this.m_bodyList; seed; seed = seed.m_next) {
if (seed.m_flags & b2Body.e_islandFlag) {
continue;
}
if (seed.IsAwake() == false || seed.IsActive() == false) {
continue;
}
if (seed.GetType() == b2Body.b2_staticBody) {
continue;
}
island.Clear();
var stackCount = 0;
stack[stackCount++] = seed;
seed.m_flags |= b2Body.e_islandFlag;
while (stackCount > 0) {
b = stack[--stackCount];
island.AddBody(b);
if (b.IsAwake() == false) {
b.SetAwake(true);
}
if (b.GetType() == b2Body.b2_staticBody) {
continue;
}
var other;
for (var ce = b.m_contactList; ce; ce = ce.next) {
if (ce.contact.m_flags & b2Contact.e_islandFlag) {
continue;
}
if (ce.contact.IsSensor() == true || ce.contact.IsEnabled() == false || ce.contact.IsTouching() == false) {
continue;
}
island.AddContact(ce.contact);
ce.contact.m_flags |= b2Contact.e_islandFlag;
other = ce.other;
if (other.m_flags & b2Body.e_islandFlag) {
continue;
}
stack[stackCount++] = other;
other.m_flags |= b2Body.e_islandFlag;
}
for (var jn = b.m_jointList; jn; jn = jn.next) {
if (jn.joint.m_islandFlag == true) {
continue;
}
other = jn.other;
if (other.IsActive() == false) {
continue;
}
island.AddJoint(jn.joint);
jn.joint.m_islandFlag = true;
if (other.m_flags & b2Body.e_islandFlag) {
continue;
}
stack[stackCount++] = other;
other.m_flags |= b2Body.e_islandFlag;
}
}
island.Solve(step, this.m_gravity, this.m_allowSleep);
for (var i = 0; i < island.m_bodyCount; ++i) {
b = island.m_bodies[i];
if (b.GetType() == b2Body.b2_staticBody) {
b.m_flags &= ~b2Body.e_islandFlag;
}
}
}
for (i = 0;
i < stack.length; ++i) {
if (!stack[i]) break;
stack[i] = null;
}
for (b = this.m_bodyList;
b; b = b.m_next) {
if (b.IsAwake() == false || b.IsActive() == false) {
continue;
}
if (b.GetType() == b2Body.b2_staticBody) {
continue;
}
b.SynchronizeFixtures();
}
this.m_contactManager.FindNewContacts();
}
when a new fixture is created
b2Body.prototype.CreateFixture = function (def) {
if (this.m_world.IsLocked() == true) {
return null;
}
var fixture = new b2Fixture();
fixture.Create(this, this.m_xf, def);
if (this.m_flags & b2Body.e_activeFlag) {
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
fixture.CreateProxy(broadPhase, this.m_xf);
}
fixture.m_next = this.m_fixtureList;
this.m_fixtureList = fixture;
++this.m_fixtureCount;
fixture.m_body = this;
if (fixture.m_density > 0.0) {
this.ResetMassData();
}
this.m_world.m_flags |= b2World.e_newFixture;
return fixture;
}
when the position of body is changed
b2Body.prototype.SetPositionAndAngle = function (position, angle) {
if (angle === undefined) angle = 0;
var f;
if (this.m_world.IsLocked() == true) {
return;
}
this.m_xf.R.Set(angle);
this.m_xf.position.SetV(position);
var tMat = this.m_xf.R;
var tVec = this.m_sweep.localCenter;
this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
this.m_sweep.c.x += this.m_xf.position.x;
this.m_sweep.c.y += this.m_xf.position.y;
this.m_sweep.c0.SetV(this.m_sweep.c);
this.m_sweep.a0 = this.m_sweep.a = angle;
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
for (f = this.m_fixtureList;
f; f = f.m_next) {
f.Synchronize(broadPhase, this.m_xf, this.m_xf);
}
this.m_world.m_contactManager.FindNewContacts();
}
synchronize
b2Body.prototype.SynchronizeFixtures = function () {
var xf1 = b2Body.s_xf1;
xf1.R.Set(this.m_sweep.a0);
var tMat = xf1.R;
var tVec = this.m_sweep.localCenter;
xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
var f;
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
for (f = this.m_fixtureList;
f; f = f.m_next) {
f.Synchronize(broadPhase, xf1, this.m_xf);
}
}
b2contractmanager instantiate
b2ContactManager.prototype.b2ContactManager = function () {
this.m_world = null;
this.m_contactCount = 0;
this.m_contactFilter = b2ContactFilter.b2_defaultFilter;
this.m_contactListener = b2ContactListener.b2_defaultListener;
this.m_contactFactory = new b2ContactFactory(this.m_allocator);
this.m_broadPhase = new b2DynamicTreeBroadPhase();
}
contactmanager addpair
b2ContactManager.prototype.AddPair = function (proxyUserDataA, proxyUserDataB) {
var fixtureA = (proxyUserDataA instanceof b2Fixture ? proxyUserDataA : null);
var fixtureB = (proxyUserDataB instanceof b2Fixture ? proxyUserDataB : null);
var bodyA = fixtureA.GetBody();
var bodyB = fixtureB.GetBody();
if (bodyA == bodyB) return;
var edge = bodyB.GetContactList();
while (edge) {
if (edge.other == bodyA) {
var fA = edge.contact.GetFixtureA();
var fB = edge.contact.GetFixtureB();
if (fA == fixtureA && fB == fixtureB) return;
if (fA == fixtureB && fB == fixtureA) return;
}
edge = edge.next;
}
if (bodyB.ShouldCollide(bodyA) == false) {
return;
}
if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) {
return;
}
var c = this.m_contactFactory.Create(fixtureA, fixtureB);
fixtureA = c.GetFixtureA();
fixtureB = c.GetFixtureB();
bodyA = fixtureA.m_body;
bodyB = fixtureB.m_body;
c.m_prev = null;
c.m_next = this.m_world.m_contactList;
if (this.m_world.m_contactList != null) {
this.m_world.m_contactList.m_prev = c;
}
this.m_world.m_contactList = c;
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;
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;
++this.m_world.m_contactCount;
return;
}
contactmanager.findnewcontacts
b2ContactManager.prototype.FindNewContacts = function () {
this.m_broadPhase.UpdatePairs(Box2D.generateCallback(this, this.AddPair));
}
b2DynamicTreeBroadPhase.prototype.UpdatePairs = function (callback) {
var __this = this;
__this.m_pairCount = 0;
var i = 0,
queryProxy;
for (i = 0;
i < __this.m_moveBuffer.length; ++i) {
queryProxy = __this.m_moveBuffer[i];
function QueryCallback(proxy) {
if (proxy == queryProxy) return true;
if (__this.m_pairCount == __this.m_pairBuffer.length) {
__this.m_pairBuffer[__this.m_pairCount] = new b2DynamicTreePair();
}
var pair = __this.m_pairBuffer[__this.m_pairCount];
pair.proxyA = proxy < queryProxy ? proxy : queryProxy;
pair.proxyB = proxy >= queryProxy ? proxy : queryProxy;++__this.m_pairCount;
return true;
};
var fatAABB = __this.m_tree.GetFatAABB(queryProxy);
__this.m_tree.Query(QueryCallback, fatAABB);
}
__this.m_moveBuffer.length = 0;
for (var i = 0; i < __this.m_pairCount;) {
var primaryPair = __this.m_pairBuffer[i];
var userDataA = __this.m_tree.GetUserData(primaryPair.proxyA);
var userDataB = __this.m_tree.GetUserData(primaryPair.proxyB);
callback(userDataA, userDataB);
++i;
while (i < __this.m_pairCount) {
var pair = __this.m_pairBuffer[i];
if (pair.proxyA != primaryPair.proxyA || pair.proxyB != primaryPair.proxyB) {
break;
}++i;
}
}
}
destroy
b2ContactManager.prototype.Destroy = function (c) {
var fixtureA = c.GetFixtureA();
var fixtureB = c.GetFixtureB();
var bodyA = fixtureA.GetBody();
var bodyB = fixtureB.GetBody();
if (c.IsTouching()) {
this.m_contactListener.EndContact(c);
}
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 == this.m_world.m_contactList) {
this.m_world.m_contactList = c.m_next;
}
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;
}
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;
}
this.m_contactFactory.Destroy(c);
--this.m_contactCount;
}
contactmanager collide
b2ContactManager.prototype.Collide = function () {
var c = this.m_world.m_contactList;
while (c) {
var fixtureA = c.GetFixtureA();
var fixtureB = c.GetFixtureB();
var bodyA = fixtureA.GetBody();
var bodyB = fixtureB.GetBody();
if (bodyA.IsAwake() == false && bodyB.IsAwake() == false) {
c = c.GetNext();
continue;
}
if (c.m_flags & b2Contact.e_filterFlag) {
if (bodyB.ShouldCollide(bodyA) == false) {
var cNuke = c;
c = cNuke.GetNext();
this.Destroy(cNuke);
continue;
}
if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) {
cNuke = c;
c = cNuke.GetNext();
this.Destroy(cNuke);
continue;
}
c.m_flags &= ~b2Contact.e_filterFlag;
}
var proxyA = fixtureA.m_proxy;
var proxyB = fixtureB.m_proxy;
var overlap = this.m_broadPhase.TestOverlap(proxyA, proxyB);
if (overlap == false) {
cNuke = c;
c = cNuke.GetNext();
this.Destroy(cNuke);
continue;
}
c.Update(this.m_contactListener);
c = c.GetNext();
}
}