/* * 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.Collision.Shapes{ import Box2D.Common.Math.*; import Box2D.Common.*; import Box2D.Dynamics.*; import Box2D.Collision.*; /// A shape is used for collision detection. Shapes are created in b2World. /// You can use shape for collision detection before they are attached to the world. /// @warning you cannot reuse shapes. public class b2Shape { /// Get the type of this shape. You can use this to down cast to the concrete shape. /// @return the shape type. public function GetType() : int{ return m_type; } /// Is this shape a sensor (non-solid)? /// @return the true if the shape is a sensor. public function IsSensor() : Boolean{ return m_isSensor; } /// Set the contact filtering data. You must call b2World::Refilter to correct /// existing contacts/non-contacts. public function SetFilterData(filter:b2FilterData) : void { m_filter = filter.Copy(); } /// Get the contact filtering data. public function GetFilterData() : b2FilterData { return m_filter.Copy(); } /// Get the parent body of this shape. This is NULL if the shape is not attached. /// @return the parent body. public function GetBody() : b2Body{ return m_body; } /// Get the next shape in the parent body's shape list. /// @return the next shape. public function GetNext() : b2Shape{ return m_next; } /// Get the user data that was assigned in the shape definition. Use this to /// store your application specific data. public function GetUserData() : *{ return m_userData; } /// Set the user data. Use this to store your application specific data. public function SetUserData(data:*) : void { m_userData = data; } /// Test a point for containment in this shape. This only works for convex shapes. /// @param xf the shape world transform. /// @param p a point in world coordinates. public virtual function TestPoint(xf:b2XForm, p:b2Vec2) : Boolean {return false}; /// Perform a ray cast against this shape. /// @param xf the shape world transform. /// @param lambda returns the hit fraction. You can use this to compute the contact point /// p = (1 - lambda) * segment.p1 + lambda * segment.p2. /// @param normal returns the normal at the contact point. If there is no intersection, the normal /// is not set. /// @param segment defines the begin and end point of the ray cast. /// @param maxLambda a number typically in the range [0,1]. /// @return e_hitCollide if there was an intersection, e_startsInsideCollide if the point is inside and e_missCollide otherwise public virtual function TestSegment(xf:b2XForm, lambda:Array, // float pointer normal:b2Vec2, // pointer segment:b2Segment, maxLambda:Number) : int {return e_missCollide}; /// Given a transform, compute the associated axis aligned bounding box for this shape. /// @param aabb returns the axis aligned box. /// @param xf the world transform of the shape. public virtual function ComputeAABB(aabb:b2AABB, xf:b2XForm) : void {}; /// Given two transforms, compute the associated swept axis aligned bounding box for this shape. /// @param aabb returns the axis aligned box. /// @param xf1 the starting shape world transform. /// @param xf2 the ending shape world transform. public virtual function ComputeSweptAABB( aabb:b2AABB, xf1:b2XForm, xf2:b2XForm) : void {}; /// Compute the mass properties of this shape using its dimensions and density. /// The inertia tensor is computed about the local origin, not the centroid. /// @param massData returns the mass data for this shape. public virtual function ComputeMass(massData:b2MassData) : void {}; /// Get the maximum radius about the parent body's center of mass. public function GetSweepRadius() : Number { return m_sweepRadius; } /// Get the coefficient of friction. public function GetFriction() : Number { return m_friction; } /// Get the coefficient of restitution. public function GetRestitution() : Number { return m_restitution; } //--------------- Internals Below ------------------- static public function Create(def:b2ShapeDef, allocator:*) : b2Shape { switch (def.type) { case e_circleShape: { //void* mem = allocator->Allocate(sizeof(b2CircleShape)); return new b2CircleShape(def); } case e_polygonShape: { //void* mem = allocator->Allocate(sizeof(b2PolygonShape)); return new b2PolygonShape(def); } default: //b2Settings.b2Assert(false); return null; } } static public function Destroy(shape:b2Shape, allocator:*) : void { /*switch (s.m_type) { case e_circleShape: //s->~b2Shape(); //allocator->Free(s, sizeof(b2CircleShape)); break; case e_polygonShape: //s->~b2Shape(); //allocator->Free(s, sizeof(b2PolygonShape)); break; default: //b2Settings.b2Assert(false); }*/ } public function b2Shape(def:b2ShapeDef){ m_userData = def.userData; m_friction = def.friction; m_restitution = def.restitution; m_density = def.density; m_body = null; m_sweepRadius = 0.0; m_next = null; m_proxyId = b2Pair.b2_nullProxy; m_filter = def.filter.Copy(); m_isSensor = def.isSensor; } //virtual ~b2Shape(); // static private var s_proxyAABB:b2AABB = new b2AABB(); public function CreateProxy(broadPhase:b2BroadPhase, transform:b2XForm) : void{ //b2Settings.b2Assert(m_proxyId == b2_nullProxy); var aabb:b2AABB = s_proxyAABB; ComputeAABB(aabb, transform); var inRange:Boolean = broadPhase.InRange(aabb); // You are creating a shape outside the world box. //b2Settings.b2Assert(inRange); if (inRange) { m_proxyId = broadPhase.CreateProxy(aabb, this); } else { m_proxyId = b2Pair.b2_nullProxy; } } public function DestroyProxy(broadPhase:b2BroadPhase) : void{ if (m_proxyId != b2Pair.b2_nullProxy) { broadPhase.DestroyProxy(m_proxyId); m_proxyId = b2Pair.b2_nullProxy; } } // static private var s_syncAABB:b2AABB = new b2AABB(); // public function Synchronize(broadPhase:b2BroadPhase, transform1:b2XForm, transform2:b2XForm) : Boolean{ if (m_proxyId == b2Pair.b2_nullProxy) { return false; } // Compute an AABB that covers the swept shape (may miss some rotation effect). var aabb:b2AABB = s_syncAABB; ComputeSweptAABB(aabb, transform1, transform2); if (broadPhase.InRange(aabb)) { broadPhase.MoveProxy(m_proxyId, aabb); return true; } else { return false; } } static private var s_resetAABB:b2AABB = new b2AABB(); public function RefilterProxy(broadPhase:b2BroadPhase, transform:b2XForm) : void{ if (m_proxyId == b2Pair.b2_nullProxy) { return; } broadPhase.DestroyProxy(m_proxyId); var aabb:b2AABB = s_resetAABB; ComputeAABB(aabb, transform); var inRange:Boolean = broadPhase.InRange(aabb); if (inRange) { m_proxyId = broadPhase.CreateProxy(aabb, this); } else { m_proxyId = b2Pair.b2_nullProxy; } } public virtual function UpdateSweepRadius(center:b2Vec2) : void{}; public var m_type:int; public var m_next:b2Shape; public var m_body:b2Body; // Sweep radius relative to the parent body's center of mass. public var m_sweepRadius:Number; public var m_density:Number; public var m_friction:Number; public var m_restitution:Number; public var m_proxyId:uint; public var m_filter:b2FilterData; public var m_isSensor:Boolean; public var m_userData:*; /// The various collision shape types supported by Box2D. //enum b2ShapeType //{ static public const e_unknownShape:int = -1; static public const e_circleShape:int = 0; static public const e_polygonShape:int = 1; static public const e_shapeTypeCount:int = 2; //}; /// Possible return values for TestSegment static public const e_hitCollide:int = 1; static public const e_missCollide:int = 0; static public const e_startsInsideCollide:int = -1; }; }