Rolling a Sphere with Keyboard and Box2DFlash Physics
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.
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); } } }
Papervision3D with Box2DFlash Part 4 – Distance Joint
Please check the previous examples on box2dflash before jumping into this one.
This time around, we’re going to create a “Distance Joint” on the large heavy box in the middle:
private function createDistanceJoint():void { var boxWidth:Number = 50; var boxBody:b2BodyDef = new b2BodyDef(); boxBody.position = new b2Vec2(WIDTH/2/WORLD_SCALE, 420/WORLD_SCALE); var box:b2Body = world.CreateBody(boxBody); var boxShape:b2PolygonDef = new b2PolygonDef(); boxShape.SetAsBox(boxWidth/WORLD_SCALE, boxWidth/WORLD_SCALE); 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:b2MassData = new b2MassData(); massData.mass = 1000; box.SetMass(massData); var joint:b2DistanceJointDef = new b2DistanceJointDef(); var anchor:b2Vec2 = new b2Vec2(); anchor = new b2Vec2(WIDTH/2/WORLD_SCALE, 250/WORLD_SCALE); joint.Initialize(box, world.m_groundBody, box.GetWorldCenter(), anchor); world.CreateJoint(joint); //start the box swinging box.m_linearVelocity = new b2Vec2(10, 0); var materialsList:MaterialsList = new MaterialsList(); materialsList.addMaterial(new WireframeMaterial(0xcc0000, 1, 6), "all"); var cube:Cube = new Cube(materialsList, boxWidth * 2, boxWidth * 2, boxWidth * 2); scene.addChild(cube); box.m_userData = cube; }
Papervision3D with Box2DFlash – Part 3 Adding Mouse Interaction
Please view the previous posts on Box2DFlash.
In part 3, we’re adding the ability to drag objects around with the mouse:
private var mousePVec:b2Vec2 = new b2Vec2(); private var mouseJoint:b2MouseJoint; private var mouseXWorldPhys:Number; private var mouseYWorldPhys:Number; private var isMouseDown:Boolean = false;
private function setupMouseEvents():void { stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); 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/WORLD_SCALE; mouseYWorldPhys = mouseY/WORLD_SCALE; } private function mouseDrag():void{ // mouse press if (isMouseDown && !mouseJoint){ //refer to 'getBodyAtMouse()' below var body:b2Body = getBodyAtMouse(); if (body) { var md:b2MouseJointDef = new b2MouseJointDef(); md.body1 = world.m_groundBody; md.body2 = body; md.target = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys); md.maxForce = 300.0 * body.m_mass; md.timeStep = timeStep; mouseJoint = world.CreateJoint(md) as b2MouseJoint; body.WakeUp(); } } // mouse release if (!isMouseDown){ if (mouseJoint){ world.DestroyJoint(mouseJoint); mouseJoint = null; } } // mouse move if (mouseJoint) { var p2:b2Vec2 = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys); mouseJoint.m_target = p2; } } public function getBodyAtMouse(isStaticIncluded:Boolean=false):b2Body{ // Make a small box. mousePVec = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys); var aabb:b2AABB = new b2AABB(); aabb.lowerBound = new b2Vec2(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001); aabb.upperBound = new b2Vec2(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:b2Body = null; for (var i:int = 0; i < count; ++i) { var shape:b2Shape = shapes[i] as b2Shape; var inside:Boolean = shape.TestPoint(shape.m_body.GetXForm(), mousePVec); if (inside) { body = shape.m_body; break; } } return body; }
override protected function onRenderTick(event:Event=null):void { updateMouseWorld(); mouseDrag(); [...]
*note – I also added a ceiling
Papervision3D with Box2DFlash Part 2
Please view the previous “Hello World” example before looking at this one.
In part 2, we’re adding walls and cubes with the code below:
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 createCubes():void { for (var i:Number = 0; i < 10; i++) { var boxWidth:Number = Math.random() * 20 + 10; var boxBody:b2BodyDef = new b2BodyDef(); boxBody.position = new b2Vec2(Math.random() * WIDTH / WORLD_SCALE, Math.random() * 50 /WORLD_SCALE); var box:b2Body = world.CreateBody(boxBody); var boxShape:b2PolygonDef = new b2PolygonDef(); boxShape.SetAsBox(boxWidth/WORLD_SCALE, boxWidth/WORLD_SCALE); boxShape.density = .7; boxShape.friction = .3; boxShape.restitution = .9; box.CreateShape(boxShape); box.SetMassFromShapes(); var materialsList:MaterialsList = new MaterialsList(); materialsList.addMaterial(new WireframeMaterial(Math.random() * 0xffffff), "all"); var cube:Cube = new Cube(materialsList, boxWidth * 2, boxWidth * 2, boxWidth * 2); scene.addChild(cube); box.m_userData = cube; } }
Search
Recommended Books
Speaking at FITC Toronto
Recent Posts
- Moving to johnlindquist.com
- AsyncCommand with Robotlegs, Signals, Flight, MinimalComps
- Search Widget – Robotlegs, Signals, Flight, Minimal Comps, Yahoo Astra
- FDT Super Awesome March Deal
- haXe Tutorial
- AS3 Signals Tutorial
- Preferred Video Tutorial Resolution?
- TweenMax – Tweening a timeline (Advanced Tweening)
- Robotlegs + Flight + Union Platform
- Back in the saddle
- Eclipse Theme Designer Preview
- RobotLegs Hello World Video Tutorial
- 10 Things Every Senior Flash Developer Should Know
- Efflex – 3D Effects for Flex
- MorphController – Mighty Morphing Papervision3D
Recent Comments
- Ocatarinabelachichix on about
- Rajiv on faq
- Rajiv on 3ds max texture baking for Papervision3D
- Anupam Biswas on Maya Texture Baking
- Anupam Biswas on Maya Texture Baking
- Arindam Mojumder on requests
- Arindam Mojumder on requests
- Arindam Mojumder on Full Screen Cube
- Arindam Mojumder on faq
- Mimosa123321 on requests
Categories
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « May | ||||||
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 | |
Archives
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





