PushButton game engine which arrived to the open source world at March 2009, has earned much community supports since then. It also has Box2D physics engine built-in but unfortunately its example was done using XML templates which some people may not like… so here is a basic Box2D setup in the code (You will need PBE 1.0):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package { import com.pblabs.engine.PBE; [SWF(width="800", height="600", frameRate="30")] public class Game extends Sprite { public function Game() { PBE.startup(this); createScene(); createBox2DManager(); createBall(); createBrick(); } private function createScene():void {} private function createBox2DManager():void {} private function createBall():void {} private function createBrick():void {} } |
What we need to do first is to create scene then box2D manager (debugger if needed) and setup ball and brick entities. Since PushButton is component based, you will see the full code below that adds a few components into each entity (the code should be self-explainable with comments):
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | package { import com.pblabs.box2D.Box2DDebugComponent; import com.pblabs.box2D.Box2DManagerComponent; import com.pblabs.box2D.Box2DSpatialComponent; import com.pblabs.box2D.CircleCollisionShape; import com.pblabs.box2D.PolygonCollisionShape; import com.pblabs.engine.PBE; import com.pblabs.engine.core.InputMap; import com.pblabs.engine.core.ObjectType; import com.pblabs.engine.entity.IEntity; import com.pblabs.engine.entity.PropertyReference; import com.pblabs.rendering2D.SimpleShapeRenderer; import com.pblabs.rendering2D.SpriteRenderer; import com.pblabs.rendering2D.SpriteSheetRenderer; import com.pblabs.rendering2D.spritesheet.SpriteSheetComponent; import com.pblabs.rendering2D.ui.SceneView; import flash.display.Sprite; import flash.geom.Point; import flash.geom.Rectangle; [SWF(width="800", height="600", frameRate="30")] public class Game extends Sprite { public function Game() { PBE.startup(this); createScene(); createBox2DManager(); createBall(); createBrick(); } private function createScene():void { var sceneView:SceneView = new SceneView(); sceneView.width = 800; sceneView.height = 600; PBE.initializeScene(sceneView); } private function createBox2DManager():void { // Create manager component. var comp:Box2DManagerComponent = new Box2DManagerComponent(); // Allocate new entity and add components. var myEntity:IEntity = PBE.allocateEntity(); myEntity.addComponent(comp, "Manager"); myEntity.initialize("SpatialManager"); } private function createBall():void { // Create spatial component. var spatialComp:Box2DSpatialComponent = new Box2DSpatialComponent(); spatialComp.spatialManager = PBE.lookupEntity("SpatialManager").lookupComponentByName("Manager") as Box2DManagerComponent; spatialComp.canMove = true; spatialComp.canRotate = true; spatialComp.canSleep = false; spatialComp.position = new Point(0, -300); spatialComp.size = new Point(60, 60); spatialComp.collisionType = new ObjectType("Ball"); spatialComp.collidesWithTypes = new ObjectType("Brick"); // Collision shape. var shape:CircleCollisionShape = new CircleCollisionShape(); shape.radius = 1.0; shape.density = 1; // Add the shape to spatial component. spatialComp.collisionShapes = new Array(); spatialComp.collisionShapes.push(shape); // Create input component. var gameInput:GameInput = new GameInput(); gameInput.input = new InputMap(); gameInput.velocityReference = new PropertyReference("@Spatial.linearVelocity"); // Create renderer component. var renderer:SimpleShapeRenderer = new SimpleShapeRenderer(); renderer.fillColor = 0xdddddd; renderer.isCircle = true; renderer.lineColor = 0x000000; renderer.scene = PBE.scene; renderer.positionProperty = new PropertyReference("@Spatial.position"); renderer.rotationProperty = new PropertyReference("@Spatial.rotation"); renderer.sizeProperty = new PropertyReference("@Spatial.size"); // Allocate new entity and add components. var myEntity:IEntity = PBE.allocateEntity(); myEntity.addComponent(spatialComp, "Spatial"); myEntity.addComponent(gameInput, "Input"); myEntity.addComponent(renderer, "Render"); myEntity.initialize("Ball"); } private function createBrick():void { // Create spatial component. var spatialComp:Box2DSpatialComponent = new Box2DSpatialComponent(); spatialComp.spatialManager = PBE.lookupEntity("SpatialManager").lookupComponentByName("Manager") as Box2DManagerComponent; spatialComp.position = new Point(0, 0); spatialComp.size = new Point(250, 60); spatialComp.canMove = false; spatialComp.canRotate = false; spatialComp.collisionType = new ObjectType("Brick"); spatialComp.collidesWithTypes = new ObjectType("Ball"); // Collision shape. var shape:PolygonCollisionShape = new PolygonCollisionShape(); shape.vertices = [new Point(-1, -1), new Point(1, -1), new Point(1, 1), new Point(-1, 1)]; shape.density = 1; // Add the shape to spatial component. spatialComp.collisionShapes = new Array(); spatialComp.collisionShapes.push(shape); // Create renderer component. var renderer:SimpleShapeRenderer = new SimpleShapeRenderer(); renderer.fillColor = 0xdddd00; renderer.isCircle = false; renderer.isSquare = true; renderer.lineColor = 0x000000; renderer.scene = PBE.scene; renderer.positionProperty = new PropertyReference("@Spatial.position"); renderer.rotationProperty = new PropertyReference("@Spatial.rotation"); renderer.sizeProperty = new PropertyReference("@Spatial.size"); // Allocate new entity and add components. var myEntity:IEntity = PBE.allocateEntity(); myEntity.addComponent(spatialComp, "Spatial"); myEntity.addComponent(renderer, "Renderer"); myEntity.initialize("Brick"); } } } |
You will also need GameInput class for input component to control the ball:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | package { import com.pblabs.box2D.CollisionEvent; import com.pblabs.engine.PBE; import com.pblabs.engine.components.TickedComponent; import com.pblabs.engine.core.InputKey; import com.pblabs.engine.core.InputMap; import com.pblabs.engine.entity.EntityComponent; import com.pblabs.engine.entity.PropertyReference; import flash.geom.Point; public class GameInput extends TickedComponent { [TypeHint(type="flash.geom.Point")] public var velocityReference:PropertyReference; private var _inputMap:InputMap; private var _left:Number = 0; private var _right:Number = 0; private var _jump:Number = 0; private var _onGround:int = 0; public function get input():InputMap { return _inputMap; } public function set input(value:InputMap):void { _inputMap = value; if (_inputMap != null) { _inputMap.mapKeyToHandler(InputKey.LEFT, onLeft); _inputMap.mapKeyToHandler(InputKey.RIGHT, onRight); _inputMap.mapKeyToHandler(InputKey.SPACE, onJump); } } override public function onTick(tickRate:Number):void { var move:Number = _right - _left; var velocity:Point = owner.getProperty(velocityReference); velocity.x = move * 100; if (_jump > 0) { velocity.y -= 200; _jump = 0; } owner.setProperty(velocityReference, velocity); } override protected function onAdd():void { super.onAdd(); owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT, onCollision); owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_STOPPED_EVENT, onCollisionEnd); } override protected function onRemove():void { super.onRemove(); owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_EVENT, onCollision); owner.eventDispatcher.removeEventListener(CollisionEvent.COLLISION_STOPPED_EVENT, onCollisionEnd); } private function onCollision(event:CollisionEvent):void { if (PBE.objectTypeManager.doesTypeOverlap(event.collidee.collisionType, "Brick")) { if (event.normal.y > 0.7) _onGround++; } if (PBE.objectTypeManager.doesTypeOverlap(event.collider.collisionType, "Brick")) { if (event.normal.y < -0.7) _onGround++; } } private function onCollisionEnd(event:CollisionEvent):void { if (PBE.objectTypeManager.doesTypeOverlap(event.collidee.collisionType, "Brick")) { if (event.normal.y > 0.7) _onGround--; } if (PBE.objectTypeManager.doesTypeOverlap(event.collider.collisionType, "Brick")) { if (event.normal.y < -0.7) _onGround--; } } private function onLeft(value:Number):void { _left = value; } private function onRight(value:Number):void { _right = value; } private function onJump(value:Number):void { if (_onGround > 0) _jump = value; } } } |
And if you need to debug box2D then add the code below:
1 2 3 4 5 6 7 8 9 10 11 | private function createBox2DDebugger():void { // Create debugger component. var comp:Box2DDebugComponent = new Box2DDebugComponent(); comp.spatialManager = PBE.lookupEntity("SpatialManager").lookupComponentByName("Manager") as Box2DManagerComponent; comp.scene = PBE.scene; // Allocate new entity and add components. var myEntity:IEntity = PBE.allocateEntity(); myEntity.addComponent(comp, "Debug"); myEntity.initialize("SpatialDebugger"); } |
This should get you start!!
4 users commented in " PushButton Box2D Tutorial "
Follow-up comment rss or Leave a TrackbackFINALLY!! A clean and well organized PBE Tutorial.
Thanks for taking the time and putting this together.
Thanks for this great tutorial.
Great Tutorial! Thanks!
Hi, great tutorial. But I’ve noticed that ball is not moving in a very natural way, thats because ball velocity is being set, not the forces which effect on a ball body. I’ve made a few changes in class GameInput and balls behavior looks little bit more natural than it used to. Check it out: http://goo.gl/1ktOO
Leave A Reply