Talking about Actionscript 3 and Box2D.
About a year ago I published a Box2D tutorial for the absolute beginners.
With 2.1 release, a lot of things changed, so it’s time to publish another tutorial for the absolute beginners.
In this tutorial we’ll cover needed libraries to import, world creation, debug draw and the creation of static and dynamic boxes and circles. And obviously the simulation itself
This is the movie we are going to make:
And this is the script used to do it:
package {
import flash.display.Sprite;
import flash.events.Event;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
public class absolute extends Sprite {
public var world:b2World=new b2World(new b2Vec2(0,10.0),true);
public var world_scale:int=30;
public function absolute():void {
debug_draw();
draw_box(250,300,500,100,false);
draw_box(250,100,100,100,true);
draw_circle(100,100,50,false);
draw_circle(400,100,50,true);
addEventListener(Event.ENTER_FRAME, update);
}
public function draw_circle(px,py,r,d):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_circle:b2CircleShape=new b2CircleShape(r/world_scale);
var my_fixture:b2FixtureDef = new b2FixtureDef();
my_fixture.shape=my_circle;
var world_body:b2Body=world.CreateBody(my_body);
world_body.CreateFixture(my_fixture);
}
public function draw_box(px,py,w,h,d):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.CreateFixture(my_fixture);
}
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);
}
public function update(e : Event):void {
world.Step(1/30,10,10);
world.ClearForces();
world.DrawDebugData();
}
}
}
Libraries
Libraries are imported at lines 4-7. Box2D
folder and your .fla
and .as
files must be in the same folder
World creation
The only line needed to create an empty world is line 9. The world class is b2World
and you must pass two parameters:
* the first one is a vector representing the world gravity.
* the second one is a boolean that allows you to improve performance by not simulating inactive bodies. In Box2D terminology, an inactive body is called “sleeping body”.
Now the world is ready, but you must face the problem of representing meters with pixels. Box2D works with meters, and there is a rule saying 1 meter = 30pixels. That’s why at line 10 I am declaring world_scale
at 30
. You can find more information about pixels and meters at this post.
Debug draw
As you should know, Box2D does not render the scene, it’s up to you attaching real objects to Box2D bodies. Anyway, there is a debug environment you can see at lines 44-52. This is the simplest debug draw you can make: basically you create a sprite and assign it to a b2DebugDraw class. More theory about debug draw theory at this post.
There are more options to configure the debug draw, but at the moment we are keeping things as simpler as we can. Notice at line 49 how I am setting the debug scale at the same value of the world scale.
Creation of a box
The most basic box is defined by an origin (the centre of the box), a width and an height. We are doing it at lines 31-43.
Let’s see the anatomy of a simple Box2D box.
A box is a body that must be static or dynamic. Only dynamic boxes are affected by gravity, collisions and physics forces. Static ones remain immovable.
Once we create a body (line 32) place it into the world (line 33) and set it as dynamic or not (lines 34-36), we just created a generic body.
It’s time to create a polygon shape (line 37) and define it as a box (line 38). Notice when I define the shape as a box, both width and height are divided by the world scale and by 2. The second division is necessary because the SetAsBox
function wants the half width and the half height.
Now we have a body and a polygon. It’s time to create a fixture. The fixture will hold various attributes such as density and restitution, but at the moment to keep things easy I just want to create a fixture (line 39) and assigning it the polygon shape previously created (line 40)
Then it’s time to place the generic body in the world (line 41) and to assign it the fixture previously created with the attached shape (line 42).
And finally the box is created.
Creation of a circle
The creation of a circle is very similar to the box creation, the only difference is the shape this time is a circle shape (line 25) the radius as parameter.
The simulation
We simulate the world in three steps: first we update the world (line 54) passing the amount of time to simulate (normally 1/30), the velocity constraint solver and the position constraint solver.
Constraint solvers determine how many times the engine sweeps over all the contacts and joints in the world to find the final position and velocity of each body. More iterations always yields a better simulation.
Finally we need to clear forces (line 55) to give more stability and it’s time to draw the debug data (line 56) if you are using the debug draw.
In the end…
In the end I created a large static box (line 13), a small dynamic one (line 14), a static (line 15) and a dynamic (line 16) sphere and I am updating the world at every frame (line 17).
Download the source code, library included.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.