Box2D Flash game creation tutorial – part 2
After seeing the character creation in Box2D Flash game creation tutorial – part 1, it’s time to add some coins to collect.
This process will involve some interesting Box2D features, like sensors and custom collision management.
I would suggest to read the basics of sensors at Erase Box: the tutorial and custom collision management at Creation of a Flash Stabilize! clone using Box2D – part 4.
Although they are both referred to an older Box2D version, they’ll introduce you to sensor and collisions.
Now the concept is simple: we are placing some circular sensors around the stage (the coins), then we’ll create a custom contact listener class to check whether the player is over a coin or not. If it’s over, we’ll remove the coin.
So this is the main script:
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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | package { import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Common.Math.*; public class ball02 extends Sprite { // world creation public var world:b2World=new b2World(new b2Vec2(0,10.0),true); public var world_scale:int=30; // the player public var player:b2Body; // force to apply to the player public var force:b2Vec2; // variables to store whether the keys are pressed or not // true = pressed; // false = unpressed public var left,right,up,down:Boolean=false; // declaring my custom contact listener class public var contact_listener=new custom_contact_listener(); public function ball02():void { // assigning the contact listener to the world world.SetContactListener(contact_listener); // calling debug draw function debug_draw(); // drawing the boundaries draw_box(250,400,500,10,false,"ground"); draw_box(0,200,10,400,false,"left"); draw_box(500,200,10,400,false,"right"); draw_box(250,0,500,10,false,"roof"); // adding the player at 250,200 add_player(250,200); // adding some coins for (var i:int = 1; i<=5; i++) { draw_coin(Math.random()*400+50,Math.random()*300+50,Math.random()*3+2); } // listeners needed for the game to work addEventListener(Event.ENTER_FRAME, update); stage.addEventListener(KeyboardEvent.KEY_DOWN,on_key_down); stage.addEventListener(KeyboardEvent.KEY_UP,on_key_up); } // according to the key pressed, set the proper variable to "true" public function on_key_down(e:KeyboardEvent):void { switch (e.keyCode) { case 37 : left=true; break; case 38 : up=true; break; case 39 : right=true; break; case 40 : down=true; break; } } // according to the key released, set the proper variable to "false" public function on_key_up(e:KeyboardEvent):void { switch (e.keyCode) { case 37 : left=false; break; case 38 : up=false; break; case 39 : right=false; break; case 40 : down=false; break; } } // function to draw a coin public function draw_coin(px,py,r):void { var my_body:b2BodyDef= new b2BodyDef(); my_body.position.Set(px/world_scale, py/world_scale); var my_circle:b2CircleShape=new b2CircleShape(r/world_scale); var my_fixture:b2FixtureDef = new b2FixtureDef(); my_fixture.shape=my_circle; // look! it's a sensor!! my_fixture.isSensor=true; var world_body:b2Body=world.CreateBody(my_body); world_body.CreateFixture(my_fixture); } // simple function to draw a box public function draw_box(px,py,w,h,d,ud):void { var my_body:b2BodyDef= new b2BodyDef(); my_body.position.Set(px/world_scale, py/world_scale); if (d) { my_body.type=b2Body.b2_dynamicBody; } var my_box:b2PolygonShape = new b2PolygonShape(); my_box.SetAsBox(w/2/world_scale, h/2/world_scale); var my_fixture:b2FixtureDef = new b2FixtureDef(); my_fixture.shape=my_box; var world_body:b2Body=world.CreateBody(my_body); world_body.SetUserData(ud); world_body.CreateFixture(my_fixture); } // function to add the player public function add_player(px,py):void { var my_body:b2BodyDef= new b2BodyDef(); my_body.position.Set(px/world_scale, py/world_scale); my_body.type=b2Body.b2_dynamicBody; var my_circle:b2CircleShape=new b2CircleShape(10/world_scale); var my_fixture:b2FixtureDef = new b2FixtureDef(); my_fixture.shape=my_circle; player=world.CreateBody(my_body); player.CreateFixture(my_fixture); } // debug draw public function debug_draw():void { var debug_draw:b2DebugDraw = new b2DebugDraw(); var debug_sprite:Sprite = new Sprite(); addChild(debug_sprite); debug_draw.SetSprite(debug_sprite); debug_draw.SetDrawScale(world_scale); debug_draw.SetFlags(b2DebugDraw.e_shapeBit); world.SetDebugDraw(debug_draw); } // function to be executed at every frame public function update(e:Event):void { // setting the force to null force=new b2Vec2(0,0); // according to the key(s) pressed, add the proper vector force if (left) { force.Add(new b2Vec2(-10,0)); } if (right) { force.Add(new b2Vec2(10,0)); } if (up) { force.Add(new b2Vec2(0,-20)); } if (down) { force.Add(new b2Vec2(0,5)); } // if there is any force, then apply it if (force.x||force.y) { player.ApplyForce(force,player.GetWorldCenter()); } world.Step(1/30,10,10); world.ClearForces(); // scanning through all bodies for (var worldbody:b2Body = world.GetBodyList(); worldbody; worldbody = worldbody.GetNext()) { // if a body is marked as "remove"... if (worldbody.GetUserData()=="remove") { // ... just remove it!! world.DestroyBody(worldbody); } } world.DrawDebugData(); } } } |
Let’s see the interesting lines:
Line 22: declaring my contact_listener variable, as custom_contact_listener type
Line 25: assigning my custom contact listener class to Box2D world
Lines 36-38: calling five times the draw_coin function passing three parameters: x position, y position and radius.
Lines 79-89: the draw_coin function… just a basic function that draw a circle… just notice at line 86 how I am declaring the circle as a sensor. This way the circle exists in the world but won’t physically collide with anything. Also, a sensor should be a static body, or it will fall down outside the stage as it won’t collide with anything.
Lines 150-156: scanning through all bodies to find, and eventually remove, bodies marked with remove. Such marker is handled by the custom contact listener class, located in the custom_contact_listener.as file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package { import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Joints.*; import Box2D.Dynamics.Contacts.*; import Box2D.Common.*; import Box2D.Common.Math.*; class custom_contact_listener extends b2ContactListener { override public function BeginContact(contact:b2Contact):void { // getting the fixtures that collided var fixtureA:b2Fixture=contact.GetFixtureA(); var fixtureB:b2Fixture=contact.GetFixtureB(); // if the fixture is a sensor, mark the parent body to be removed if (fixtureB.IsSensor()) { fixtureB.GetBody().SetUserData("remove"); } if (fixtureA.IsSensor()) { fixtureA.GetBody().SetUserData("remove"); } } } } |
BeginContact function will give us the fixtures involved in the collision. Then at lines 15-17 and 18-20 I am checking if the fixture is a sensor, then eventually mark its parent body to be removed.
Important: don’t try to remove the body inside this function, because bodies have a locked status while they are in the middle of a timestep, so you should remove a body only after you performed the Step (line 147 of the main file). This gave me a little headache, so you’ve been warned!
This is the result:
Pick up all little circles moving the player tapping on arrow keys.
They can be easily customized to meet the unique requirements of your project.















(19 votes, average: 4.21 out of 5)









This post has 6 comments
manish
i m in a in animation school quite wonderful
using box2d as environment makes our job easier even i do not know much programming to make something nice animation thanks
post but a question why u always wear a cap I saw your many pics on facebook
Dave Fulton
Awesome stuff! Box2D is my next area of exploration with actionscript so it’s great that you are sharing so much valuable information.
I can’t seem to get Box2D to work with CS3 though… is there a version conflict?
mike
Hi,
Your website is such a great ressource, Thank you!
Could you provide us with CS3 versions of your fla?
Thank you SO much!
A Freelancer’s Flash Bash [6] | Freelance Flash Games News
[...] Feronato has a nice little series on Box2D game creation, and compiled a list of isometric engines for flash game creation. Be sure to check it out for some [...]
Ollie
Thanks for the tutorial.
Is it possible to read the position of the sensor? It reports a position of 0,0 when I call .GetPosition
Getting a contact point between two bodies in box2d as3
[...] First of all you need your own custom class that extends b2ContactListener and add it to box2d’s world as contact listener, this is a quick tip so I’m not gonna go in detail about this, here’s a good introduction. [...]