Rolling a Sphere with Keyboard and Box2DFlash Physics

Thursday, January 15th, 2009 | examples

You really didn’t think I was just going to leave yesterday’s example with just one ball rolling around, did you? :)

Remember to click the .swf to give it focus. The main rolling ball is randomized, so the .swf will look different each time you open it.


source

The source is a mess. I basically copied and pasted code from my other Box2DFlash examples. The only real new stuff here is using the “gravityOffset” to cancel out gravity and the m_linearVelocity to set the velocity within Box2DFlash.

package
{
	import Box2D.Collision.Shapes.b2CircleDef;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2World;
 
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
 
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.core.math.Number3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.primitives.Sphere;
	import org.papervision3d.view.BasicView;
 
	[SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
	public class RollingASphereWithTheKeyboardAndBox2D extends BasicView
	{
		private static const FORWARD:Number3D = new Number3D(0, 0, 1);
		private var WORLD_SCALE:Number = 30;
		private var WIDTH:Number = 640;
		private var HEIGHT:Number = 480;
 
		private var world:b2World;
 
		private var iterations:int = 10;
		private var timeStep:Number = 1.0/30.0;
 
		private var mainBody:b2Body;
 
 		private var isDown:Boolean = false;
		private var isUp:Boolean = false;
		private var isLeft:Boolean = false;
		private var isRight:Boolean = false;
 
		public function RollingASphereWithTheKeyboardAndBox2D()
		{
			setupPapervision3D();
			createWorld();
			createFloor();
			createCeiling();
			createWalls();
			createShapes();
 
			startRendering();
 
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}
 
		private function keyDownHandler(event:KeyboardEvent):void
		{
			switch(event.keyCode)
			{
				case Keyboard.DOWN:
					isDown = true;
					break;
				case Keyboard.UP:
					isUp = true;
					break;
				case Keyboard.LEFT:
					isLeft = true;
					break;
				case Keyboard.RIGHT:
					isRight = true;
					break;
			}
		}
 
		private function keyUpHandler(event:KeyboardEvent):void
		{
			switch(event.keyCode)
			{
				case Keyboard.DOWN:
					isDown = false;
					break;
				case Keyboard.UP:
					isUp = false;
					break;
				case Keyboard.LEFT:
					isLeft = false;
					break;
				case Keyboard.RIGHT:
					isRight = false;
					break;
			}
		}
 
 
		private function createWalls():void
		{
			 var wallShapeDef:b2PolygonDef = new b2PolygonDef();
			var wallBodyDef:b2BodyDef = new b2BodyDef();
			var wall:b2Body;
 
			//Left and Right Shape Definition
			wallShapeDef.SetAsBox(100/WORLD_SCALE, (HEIGHT+40)/WORLD_SCALE/2);
 
			// Left
			wallBodyDef.position = new b2Vec2(-95 / WORLD_SCALE, HEIGHT/WORLD_SCALE/2);
			wall = world.CreateBody(wallBodyDef);
			wall.CreateShape(wallShapeDef);
 
			// Right
			wallBodyDef.position = new b2Vec2((WIDTH+95) / WORLD_SCALE, HEIGHT/WORLD_SCALE/2);
			wall = world.CreateBody(wallBodyDef);
			wall.CreateShape(wallShapeDef);
		}
 
		private function setupPapervision3D():void
		{
			camera.y = -300;
			camera.z = -300;
		}
 
		private function createWorld():void {
			var worldBounds:b2AABB = new b2AABB();
			worldBounds.lowerBound = new b2Vec2( 0, 0 );
			worldBounds.upperBound = new b2Vec2(WIDTH/WORLD_SCALE, HEIGHT/WORLD_SCALE);
 
 			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			var sleep:Boolean = true;
 
			world = new b2World(worldBounds, gravity, sleep);
		}
 
		private function createFloor():void
		{
			// Create border of boxes
			var floorShapeDef:b2PolygonDef = new b2PolygonDef();
			var floorBodyDef:b2BodyDef = new b2BodyDef();
			var floor:b2Body;
 
			//bottom shape definition
			floorShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE);
 
			// Bottom
			floorBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, (HEIGHT+95)/WORLD_SCALE);
			floor = world.CreateBody(floorBodyDef);
			floor.CreateShape(floorShapeDef);
 
			floor.SetMassFromShapes();
		}
 
		private function createCeiling():void
		{
			var ceilingShapeDef:b2PolygonDef = new b2PolygonDef();
			var ceilingBodyDef:b2BodyDef = new b2BodyDef();
			var ceiling:b2Body;
			//Top and bottom shape definition
			ceilingShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE);
 
			// Top
			ceilingBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, -95/WORLD_SCALE);
			ceiling = world.CreateBody(ceilingBodyDef);
			ceiling.CreateShape(ceilingShapeDef);
		}
 
		private function createShapes():void
		{
			var light:PointLight3D = new PointLight3D();
			for (var i:Number = 0; i < 20; i++)
			{
				//radius for physics circle and sphere
				var radius:Number = Math.random() * 50 + 10;
 
				var bodyDef:b2BodyDef = new b2BodyDef();
				//random position toward the top of the stage
				bodyDef.position = new b2Vec2(Math.random() * WIDTH / WORLD_SCALE, Math.random() * HEIGHT /WORLD_SCALE);
 
				var body:b2Body = world.CreateBody(bodyDef);
 
				var shapeDef:b2CircleDef = new b2CircleDef();
				shapeDef.radius = radius/WORLD_SCALE;
				shapeDef.density = 1;
				shapeDef.friction = .7;
				shapeDef.restitution = .7;
				body.CreateShape(shapeDef);
				body.SetMassFromShapes();
 				var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, Math.random() * 0xffffff, 0x111111);
				var sphere:Sphere = new Sphere(flatShadeMaterial, radius);
 
				scene.addChild(sphere);
				body.m_userData = sphere;
 
				mainBody = body;
			}
		}
 
		override protected function onRenderTick(event:Event=null):void
		{
			if(isDown) mainBody.m_linearVelocity.y += .2;
			if(isUp) mainBody.m_linearVelocity.y -= .2;
			if(isLeft) mainBody.m_linearVelocity.x -= .2;
			if(isRight) mainBody.m_linearVelocity.x += .2;
 
			//sets the position of any DisplayObject3D to the body position
			for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
			{
				var gravityOffset:b2Vec2 = world.m_gravity.Copy();
				gravityOffset.Multiply(-bb.m_mass);
				bb.ApplyForce(gravityOffset, bb.GetWorldCenter() );
                if (bb.m_userData is DisplayObject3D)
                {
                        bb.m_userData.x = bb.GetPosition().x * WORLD_SCALE - WIDTH * .5;
                        bb.m_userData.y = -bb.GetPosition().y * WORLD_SCALE + HEIGHT * .5;
                        var distance:Number = Math.sqrt(bb.m_linearVelocity.x * bb.m_linearVelocity.x + bb.m_linearVelocity.y * bb.m_linearVelocity.y);
 
						var rotationAxis:Number3D = Number3D.cross(new Number3D(bb.m_linearVelocity.x, bb.m_linearVelocity.y, 0), FORWARD);
						rotationAxis.normalize();
 
						var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, -rotationAxis.y, rotationAxis.z, distance/30);
 
						bb.m_userData.transform.calculateMultiply3x3(rotationMatrix, bb.m_userData.transform);
                }
			}
			renderer.renderScene(scene, camera, viewport);
			world.Step(timeStep, iterations);
		}
	}
}

Tags: , , ,

  • Could you give an idea how to choose the sphere by the click of mouse ? I dont want to be randomized...
  • J
    Question: what exactly does startRendering() call? Is it tied to extending BasicView?
  • oliver_l1
    pv3d and box2d rocks! great examples as always.
  • 3dSec
    yeh i get it now..
    but y cant we do this?
    var gravity:b2Vec2 = new b2Vec2(0.0, 0.0);
    set the gravity to zero
  • John Lindquist
    @3dSec - it's a way to nullify the gravity in box2dflash. Since gravity is required for any of the physics to work, you have to apply an opposite force to keep everything "floating". Try downloading the example and commenting out those lines and you'll see what I mean.
  • 3dSec
    can some 1 explain what's going on in this line?

    var gravityOffset:b2Vec2 = world.m_gravity.Copy();
    gravityOffset.Multiply(-bb.m_mass);
    bb.ApplyForce(gravityOffset, bb.GetWorldCenter() );
  • BeechyBoy
    Some great potential here. Thanks for posting this :)
blog comments powered by Disqus

Search

Recommended Books

Speaking at FITC Toronto

 

January 2009
M T W T F S S
« Dec   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  

Preferred Video Tutorial Resolution

  • 1024x768 (53%, 85 Votes)
  • 1280x1024 (15%, 24 Votes)
  • 1920x1080 (15%, 24 Votes)
  • 800x600 (13%, 20 Votes)
  • 480x320 (4%, 6 Votes)
  • 640x480 (0%, 2 Votes)

Total Voters: 160

Loading ... Loading ...