/* * 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.Contacts{ import Box2D.Dynamics.*; import Box2D.Dynamics.Contacts.*; import Box2D.Collision.Shapes.*; import Box2D.Collision.*; import Box2D.Common.Math.*; import Box2D.Common.*; //typedef b2Contact* b2ContactCreateFcn(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); //typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); public class b2Contact { public virtual function GetManifolds():Array{return null}; /// Get the number of manifolds. This is 0 or 1 between convex shapes. /// This may be greater than 1 for convex-vs-concave shapes. Each /// manifold holds up to two contact points with a shared contact normal. public function GetManifoldCount():int { return m_manifoldCount; } /// Is this contact solid? /// @return true if this contact should generate a response. public function IsSolid():Boolean{ return (m_flags & e_nonSolidFlag) == 0; } /// Get the next contact in the world's contact list. public function GetNext():b2Contact{ return m_next; } /// Get the first shape in this contact. public function GetShape1():b2Shape{ return m_shape1; } /// Get the second shape in this contact. public function GetShape2():b2Shape{ return m_shape2; } //--------------- Internals Below ------------------- // m_flags // enum static public var e_nonSolidFlag:uint = 0x0001; static public var e_slowFlag:uint = 0x0002; static public var e_islandFlag:uint = 0x0004; static public var e_toiFlag:uint = 0x0008; static public function AddType(createFcn:Function, destroyFcn:Function, type1:int, type2:int) : void { //b2Settings.b2Assert(b2Shape.e_unknownShape < type1 && type1 < b2Shape.e_shapeTypeCount); //b2Settings.b2Assert(b2Shape.e_unknownShape < type2 && type2 < b2Shape.e_shapeTypeCount); s_registers[type1][type2].createFcn = createFcn; s_registers[type1][type2].destroyFcn = destroyFcn; s_registers[type1][type2].primary = true; if (type1 != type2) { s_registers[type2][type1].createFcn = createFcn; s_registers[type2][type1].destroyFcn = destroyFcn; s_registers[type2][type1].primary = false; } } static public function InitializeRegisters() : void{ s_registers = new Array(b2Shape.e_shapeTypeCount); for (var i:int = 0; i < b2Shape.e_shapeTypeCount; i++){ s_registers[i] = new Array(b2Shape.e_shapeTypeCount); for (var j:int = 0; j < b2Shape.e_shapeTypeCount; j++){ s_registers[i][j] = new b2ContactRegister(); } } AddType(b2CircleContact.Create, b2CircleContact.Destroy, b2Shape.e_circleShape, b2Shape.e_circleShape); AddType(b2PolyAndCircleContact.Create, b2PolyAndCircleContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_circleShape); AddType(b2PolygonContact.Create, b2PolygonContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_polygonShape); AddType(b2ConcaveArcAndCircleContact.Create, b2ConcaveArcAndCircleContact.Destroy, b2Shape.e_concaveArcShape, b2Shape.e_circleShape); AddType(b2PolyAndConcaveArcContact.Create, b2PolyAndConcaveArcContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_concaveArcShape); AddType(b2StaticEdgeAndCircleContact.Create, b2StaticEdgeAndCircleContact.Destroy, b2Shape.e_staticEdgeShape, b2Shape.e_circleShape); AddType(b2PolyAndStaticEdgeContact.Create, b2PolyAndStaticEdgeContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_staticEdgeShape); } static public function Create(shape1:b2Shape, shape2:b2Shape, allocator:*):b2Contact{ if (s_initialized == false) { InitializeRegisters(); s_initialized = true; } var type1:int = shape1.m_type; var type2:int = shape2.m_type; //b2Settings.b2Assert(b2Shape.e_unknownShape < type1 && type1 < b2Shape.e_shapeTypeCount); //b2Settings.b2Assert(b2Shape.e_unknownShape < type2 && type2 < b2Shape.e_shapeTypeCount); var reg:b2ContactRegister = s_registers[type1][type2]; var createFcn:Function = reg.createFcn; if (createFcn != null) { if (reg.primary) { return createFcn(shape1, shape2, allocator); } else { var c:b2Contact = createFcn(shape2, shape1, allocator); for (var i:int = 0; i < c.m_manifoldCount; ++i) { var m:b2Manifold = c.GetManifolds()[ i ]; m.normal = m.normal.Negative(); } return c; } } else { return null; } } static public function Destroy(contact:b2Contact, allocator:*) : void{ //b2Settings.b2Assert(s_initialized == true); if (contact.m_manifoldCount > 0) { contact.m_shape1.m_body.WakeUp(); contact.m_shape2.m_body.WakeUp(); } var type1:int = contact.m_shape1.m_type; var type2:int = contact.m_shape2.m_type; //b2Settings.b2Assert(b2Shape.e_unknownShape < type1 && type1 < b2Shape.e_shapeTypeCount); //b2Settings.b2Assert(b2Shape.e_unknownShape < type2 && type2 < b2Shape.e_shapeTypeCount); var reg:b2ContactRegister = s_registers[type1][type2]; var destroyFcn:Function = reg.destroyFcn; destroyFcn(contact, allocator); } public function b2Contact(s1:b2Shape=null, s2:b2Shape=null) { m_flags = 0; if (!s1 || !s2){ m_shape1 = null; m_shape2 = null; return; } if (s1.IsSensor() || s2.IsSensor()) { m_flags |= e_nonSolidFlag; } m_shape1 = s1; m_shape2 = s2; m_manifoldCount = 0; m_friction = Math.sqrt(m_shape1.m_friction * m_shape2.m_friction); m_restitution = b2Math.b2Max(m_shape1.m_restitution, m_shape2.m_restitution); m_prev = null; m_next = null; m_node1.contact = null; m_node1.prev = null; m_node1.next = null; m_node1.other = null; m_node2.contact = null; m_node2.prev = null; m_node2.next = null; m_node2.other = null; } public function Update(listener:b2ContactListener) : void { var oldCount:int = m_manifoldCount; Evaluate(listener); var newCount:int = m_manifoldCount; var body1:b2Body = m_shape1.m_body; var body2:b2Body = m_shape2.m_body; if (newCount == 0 && oldCount > 0) { body1.WakeUp(); body2.WakeUp(); } // Slow contacts don't generate TOI events. if (body1.IsStatic() || body1.IsBullet() || body2.IsStatic() || body2.IsBullet()) { m_flags &= ~e_slowFlag; } else { m_flags |= e_slowFlag; } } //virtual ~b2Contact() {} public virtual function Evaluate(listener:b2ContactListener) : void{}; static public var s_registers:Array; //[][] static public var s_initialized:Boolean = false; public var m_flags:uint; // World pool and list pointers. public var m_prev:b2Contact; public var m_next:b2Contact; // Nodes for connecting bodies. public var m_node1:b2ContactEdge = new b2ContactEdge(); public var m_node2:b2ContactEdge = new b2ContactEdge(); public var m_shape1:b2Shape; public var m_shape2:b2Shape; public var m_manifoldCount:int; // Combined friction public var m_friction:Number; public var m_restitution:Number; public var m_toi:Number; }; }