You are hereBox2dExample

Box2dExample


By John Lindquist - Posted on 02 June 2008

I've been making pretty good progress on the "Refactored" syntax. Check out below to see what the current api looks like:
package{
 
	import com.suite75.quake1.utils.FPS;
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	import org.box2dflash.collision.AABB;
	import org.box2dflash.collision.shapes.CircleDef;
	import org.box2dflash.collision.shapes.MassData;
	import org.box2dflash.collision.shapes.PolygonDef;
	import org.box2dflash.collision.shapes.Shape;
	import org.box2dflash.common.math.Vec2;
	import org.box2dflash.dynamics.Body;
	import org.box2dflash.dynamics.BodyDef;
	import org.box2dflash.dynamics.DebugDraw;
	import org.box2dflash.dynamics.World;
	import org.box2dflash.dynamics.joints.DistanceJointDef;
	import org.box2dflash.dynamics.joints.MouseJoint;
	import org.box2dflash.dynamics.joints.MouseJointDef;
	/**
	* @author 	John Lindquist
	*/
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class RefactoredBox2dSpeedTest extends Sprite {
 
		private var stageWidth:Number = 640;
		private var stageHeight:Number = 480;
 
		private var world:World;
		private var gravity:Vec2 = new Vec2(0, 10);
 
		private var worldScale:Number = 30;
 
		private var iterations:int = 10;
		private var timeStep:Number = 1/30;
 
		private var debugDraw:DebugDraw;
		private var isDebugDrawing:Boolean = true;
 
		private var mouseJoint:MouseJoint;
		private var mouseXWorldPhys:Number;
		private var mouseYWorldPhys:Number;
		private var mouseXWorld:Number;
		private var mouseYWorld:Number;
 
		private var isStaticIncluded:Boolean = false;
 
		private var isMouseDown:Boolean = false;
 
		public function RefactoredBox2dSpeedTest() {
			init();
		}
 
		private function init():void
		{
			createWorld();
			createWalls();
			createShapes();
			createDistanceJoint();
			setupDebugDraw();
 
			addEventListener(Event.ADDED_TO_STAGE, setupMouseEvents);
			addEventListener(Event.ENTER_FRAME, onUpdate);
 
			var fps:FPS = new FPS(this);
			fps.x = 100;
			fps.y = 20;
		}
 
		private function createWorld():void {
			var worldBounds:AABB = new AABB();
			worldBounds.lowerBound = new Vec2( 0, 0 );
			worldBounds.upperBound = new Vec2( 640/30, 480/30);
 
 
 
			var sleep:Boolean = true;
 
			world = new World(worldBounds, gravity, sleep);
		}
 
		private function createWalls():void
		{
			// Create border of boxes
			var wallShapeDef:PolygonDef = new PolygonDef();
			var wallBodyDef:BodyDef = new BodyDef();
			var wall:Body;
 
 
			//Left and Right Shape Definition
			wallShapeDef.setAsBox(100/worldScale, (stageHeight+40)/worldScale/2);
 
			// Left
			wallBodyDef.position = new Vec2(-95 / worldScale, stageHeight/worldScale/2);
			wall = world.createBody(wallBodyDef);
			wall.createShape(wallShapeDef);
 
			// Right
			wallBodyDef.position = new Vec2((stageWidth+95) / worldScale, stageHeight/worldScale/2);
			wall = world.createBody(wallBodyDef);
			wall.createShape(wallShapeDef);
 
 
			//Top and bottom shape definition
			wallShapeDef.setAsBox((stageWidth+40)/worldScale/2, 100/worldScale);
 
			// Top
			wallBodyDef.position = new Vec2(stageWidth/worldScale/2, -95/worldScale);
			wall = world.createBody(wallBodyDef);
			wall.createShape(wallShapeDef);
 
			// Bottom
			wallBodyDef.position = new Vec2(stageWidth/worldScale/2, (stageHeight+95)/worldScale);
			wall = world.createBody(wallBodyDef);
			wall.createShape(wallShapeDef);
 
 
			wall.setMassFromShapes();
		}
 
		private function createShapes():void
		{
			for (var i:Number = 0; i < 50; i++)
			{
				var bodyDef:BodyDef = new BodyDef();
				bodyDef.position = new Vec2(Math.random() * 640 / worldScale, Math.random() * 50 /worldScale);
 
				var body:Body = world.createBody(bodyDef);
 
				var shapeDef:CircleDef = new CircleDef();
				shapeDef.radius = (Math.random() * 15 + 3)/worldScale;
				shapeDef.density = 1;
				shapeDef.friction = .3;
				shapeDef.restitution = .7;
				body.createShape(shapeDef);
				body.setMassFromShapes();
			}
		}
 
		private function setupDebugDraw():void
		{
			if(isDebugDrawing)
			{
				debugDraw = new DebugDraw();
				debugDraw.m_sprite = new Sprite();
 
				addChild(debugDraw.m_sprite);
 
				debugDraw.m_drawScale = 30;
				debugDraw.m_fillAlpha = .25;
				debugDraw.m_lineThickness = 1;
				debugDraw.m_drawFlags = /*DebugDraw.e_aabbBit | DebugDraw.e_centerOfMassBit | DebugDraw.e_coreShapeBit | DebugDraw.e_obbBit | DebugDraw.e_pairBit |*/ DebugDraw.e_shapeBit| DebugDraw.e_jointBit ;
				world.debugDraw = debugDraw;
			}
		}
 
		private function createDistanceJoint():void
		{
			var boxBody:BodyDef = new BodyDef();
			boxBody.position = new Vec2(stageWidth/2/worldScale, 420/worldScale);
 
			var box:Body = world.createBody(boxBody);
 
			var boxShape:PolygonDef = new PolygonDef();
			boxShape.setAsBox(40/worldScale, 40/worldScale);
			boxShape.density = .7;
			boxShape.friction = .3;
			boxShape.restitution = .4;
 
			box.createShape(boxShape);
 
			//instead of "SetMassFromShapes", I'm setting the box
			//mass extremely high to keep it swinging back and forth
			var massData:MassData = new MassData();
			massData.mass = 100;
 
			box.setMass(massData);
 
			var joint:DistanceJointDef = new DistanceJointDef();
			var anchor:Vec2 = new Vec2();
 
			anchor = new Vec2(stageWidth/2/worldScale, 100/worldScale);
			joint.initialize(box, world.groundBody, box.worldCenter, anchor);
 
			world.createJoint(joint);
 
			//start the box swinging
			box.linearVelocity = new Vec2(10, 0);
		}
 
		private function setupMouseEvents(event:Event):void
		{
			this.stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			this.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}
 
		private function onMouseDown(e:MouseEvent):void{isMouseDown = true;};
		private function onMouseUp(e:MouseEvent):void{isMouseDown = false;};
 
		private function updateMouseWorld():void{
			mouseXWorldPhys = mouseX/worldScale; 
			mouseYWorldPhys = mouseY/worldScale; 
 
			mouseXWorld = mouseX; 
			mouseYWorld = mouseY; 
		}
 
		private function mouseDrag():void{
			// mouse press
			if (isMouseDown && !mouseJoint){
 
				//refer to 'getBodyAtMouse()' below
				var body:Body = getBodyAtMouse();
 
				if (body)
				{
					var md:MouseJointDef = new MouseJointDef();
					md.body1 = world.groundBody;
					md.body2 = body;
					md.target = new Vec2(mouseXWorldPhys, mouseYWorldPhys);
					md.maxForce = 300.0 * body.mass;
					md.timeStep = timeStep;
					mouseJoint = world.createJoint(md) as MouseJoint;
					body.wakeUp();
				}
			}
 
			// mouse release
			if (!isMouseDown){
				if (mouseJoint){
					world.destroyJoint(mouseJoint);
					mouseJoint = null;
				}
			}
 
 
			// mouse move
			if (mouseJoint)
			{
				var p2:Vec2 = new Vec2(mouseXWorldPhys, mouseYWorldPhys);
				mouseJoint.target = p2;
			} 
		}
 
		//getBodyAtMouse()
		private var mousePVec:Vec2 = new Vec2();
		public function getBodyAtMouse(isStaticIncluded:Boolean=false):Body{
			// Make a small box.
			mousePVec = new Vec2(mouseXWorldPhys, mouseYWorldPhys);
			var aabb:AABB = new AABB();
			aabb.lowerBound = new Vec2(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
			aabb.upperBound = new Vec2(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
 
			// Query the world for overlapping shapes.
			var maxCount:int = 10;
			var shapes:Array = new Array();
			var count:int = world.query(aabb, shapes, maxCount);
			var body:Body = null;
			for (var i:int = 0; i < count; ++i)
			{
				if (shapes[i].body.isStatic == false || isStaticIncluded)
				{
					var shape:Shape = shapes[i] as Shape;
					var inside:Boolean = shape.testPoint(shape.body.getXForm(), mousePVec);
					if (inside)
					{
						body = shape.body;
						break;
					}
				}
			}
			return body;
		}
 
		private function onUpdate(e:Event):void
		{
			updateMouseWorld();
			mouseDrag();
 
			world.step(timeStep, iterations);
 
			//sets the position of any sprite to the body position
			for (var bb:Body = world.bodyList; bb; bb = bb.next)
			{
                if (bb.userData is Sprite){
                        bb.userData.x = bb.position.x * 30;
                        bb.userData.y = bb.position.y * 30;
                        bb.userData.rotation = bb.angle * (180/Math.PI);
                }
			}
		}
	}
 
}