/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ package Box2D.Dynamics{ import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Contacts.*; import Box2D.Dynamics.*; import Box2D.Common.Math.*; import Box2D.Common.*; // Delegate of b2World. public class b2ContactManager extends b2PairCallback { public function b2ContactManager() { m_world = null; m_destroyImmediate = false; }; // This is a callback from the broadphase when two AABB proxies begin // to overlap. We create a b2Contact to manage the narrow phase. public override function PairAdded(proxyUserData1:*, proxyUserData2:*):*{ var shape1:b2Shape = proxyUserData1 as b2Shape; var shape2:b2Shape = proxyUserData2 as b2Shape; var body1:b2Body = shape1.m_body; var body2:b2Body = shape2.m_body; if (body1.IsStatic() && body2.IsStatic()) { return m_nullContact; } if (shape1.m_body == shape2.m_body) { return m_nullContact; } if (body2.IsConnected(body1)) { return m_nullContact; } if (m_world.m_contactFilter != null && m_world.m_contactFilter.ShouldCollide(shape1, shape2) == false) { return m_nullContact; } // Call the factory. var c:b2Contact = b2Contact.Create(shape1, shape2, m_world.m_blockAllocator); if (c == null) { return m_nullContact; } // Contact creation may swap shapes. shape1 = c.m_shape1; shape2 = c.m_shape2; body1 = shape1.m_body; body2 = shape2.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 1 c.m_node1.contact = c; c.m_node1.other = body2; c.m_node1.prev = null; c.m_node1.next = body1.m_contactList; if (body1.m_contactList != null) { body1.m_contactList.prev = c.m_node1; } body1.m_contactList = c.m_node1; // Connect to body 2 c.m_node2.contact = c; c.m_node2.other = body1; c.m_node2.prev = null; c.m_node2.next = body2.m_contactList; if (body2.m_contactList != null) { body2.m_contactList.prev = c.m_node2; } body2.m_contactList = c.m_node2; ++m_world.m_contactCount; return c; } // This is a callback from the broadphase when two AABB proxies cease // to overlap. We retire the b2Contact. public override function PairRemoved(proxyUserData1:*, proxyUserData2:*, pairUserData:*): void{ if (pairUserData == null) { return; } var c:b2Contact = pairUserData as b2Contact; if (c == m_nullContact) { return; } // An attached body is being destroyed, we must destroy this contact // immediately to avoid orphaned shape pointers. Destroy(c); } static private const s_evalCP:b2ContactPoint = new b2ContactPoint(); public function Destroy(c:b2Contact) : void { var shape1:b2Shape = c.m_shape1; var shape2:b2Shape = c.m_shape2; // Inform the user that this contact is ending. var manifoldCount:int = c.m_manifoldCount; if (manifoldCount > 0 && m_world.m_contactListener) { var b1:b2Body = shape1.m_body; var b2:b2Body = shape2.m_body; var manifolds:Array = c.GetManifolds(); var cp:b2ContactPoint = s_evalCP; cp.shape1 = c.m_shape1; cp.shape2 = c.m_shape1; cp.friction = c.m_friction; cp.restitution = c.m_restitution; for (var i:int = 0; i < manifoldCount; ++i) { var manifold:b2Manifold = manifolds[ i ]; cp.normal.SetV(manifold.normal); for (var j:int = 0; j < manifold.pointCount; ++j) { var mp:b2ManifoldPoint = manifold.points[j]; cp.position = b1.GetWorldPoint(mp.localPoint1); var v1:b2Vec2 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); var v2:b2Vec2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); cp.separation = mp.separation; cp.id.key = mp.id._key; m_world.m_contactListener.Remove(cp); } } } // 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_world.m_contactList) { m_world.m_contactList = c.m_next; } var body1:b2Body = shape1.m_body; var body2:b2Body = shape2.m_body; // Remove from body 1 if (c.m_node1.prev) { c.m_node1.prev.next = c.m_node1.next; } if (c.m_node1.next) { c.m_node1.next.prev = c.m_node1.prev; } if (c.m_node1 == body1.m_contactList) { body1.m_contactList = c.m_node1.next; } // Remove from body 2 if (c.m_node2.prev) { c.m_node2.prev.next = c.m_node2.next; } if (c.m_node2.next) { c.m_node2.next.prev = c.m_node2.prev; } if (c.m_node2 == body2.m_contactList) { body2.m_contactList = c.m_node2.next; } // Call the factory. b2Contact.Destroy(c, m_world.m_blockAllocator); --m_world.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 function Collide() : void { // Update awake contacts. for (var c:b2Contact = m_world.m_contactList; c; c = c.m_next) { var body1:b2Body = c.m_shape1.m_body; var body2:b2Body = c.m_shape2.m_body; if (body1.IsSleeping() && body2.IsSleeping()) { continue; } c.Update(m_world.m_contactListener); } } public var m_world:b2World; // This lets us provide broadphase proxy pair user data for // contacts that shouldn't exist. public var m_nullContact:b2NullContact = new b2NullContact(); public var m_destroyImmediate:Boolean; }; }