Mar
17

Physics in ActionScript 3: Box2DFlashAS3

by Paul

I wanted to try something fun with Flash this week, so I did a quick search for “Flash Physics Engine.” Lo and behold, I struck gold. Box2DFlashAS3 is an open source ActionScript 3.0 conversion of the C++ Physics Engine Box2D. I’m very impressed with its well coded structure and easily implemented nature. I learned a few new things that will change how I code forever just by reading through their example files.


Still, they have limited resources right now as far as help documentation goes (”Please refer to the source code from the examples provided to get an idea of how to use Box2DFlash in your projects.” — that’s the ReadMe.txt that comes with it… not very helpful,huh). I thought I might give you an example of my own and walk through it step by step.

That was the thought, but it has taken me all weekend to understand the engine well enough to explain how it works. The beauty of it though, is you don’t have to understand how it works to use it.Now to get right into it then! First of all, in order to do anything with Box2DFlash you’re going to have to include most (if not all) of the files. If you have the 349KB folder “Box2D” in your project folder, then your includes will work just like this:

// Classes used in this example
 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.*;

Easy.

Now you have to create a b2World object (source code of the class is in Box2D/Dynamics/b2World.as). The world object is the entire body of the engine. Everything is contained within it once your are done.

NOTE: The brain of the engine is b2BroadPhase.as and the heart is the Step() function withing the world object. Don’t go messing with the brain (b2BroadPhase.as) ever. You will totally mess up the engine.

The world object constructor requires 3 things:
1.) A coordinate system in the form of a b2AABB class object.
2.) A vector that defines gravity. That will be in the form of a b2Vec2 class object.
3.) A boolean variable that defines whether objects “sleep” or not. (I recommend you make it true, that they can sleep)

// Create world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.minVertex.Set(-1000.0, -1000.0);
worldAABB.maxVertex.Set(1000.0, 1000.0);

// Define the gravity vector
var gravity:b2Vec2 = new b2Vec2(0.0, 300.0);

// Allow bodies to sleep
var doSleep:Boolean = true;

// Construct a world object
m_world = new b2World(worldAABB, gravity, doSleep);

My examples are not my own here. The code I’m showing is an excerpt from the “Hello World” code they provided with the engine.

After creating a world object you have to bring it to life by setting its heart to beating:

// Add event for main loop
addEventListener(Event.ENTER_FRAME, Update, false, 0, true);

public function Update(e:Event):void{
        m_world.Step(m_timeStep, m_iterations);
}

Running the Step() function every frame will update all the Body Definitions you add to your world.
As of right now this world is empty though. In order to add balls and boxes and any strange polygonal shapes you can think of, we need to create Body Definitions for them.

A Body Definition consists of 2, 3, or 4 things.
1.) A Shape Definition.
2.) An (x,y) position.
optional:
3.) Rotation (in radians)
4.)
A pre-made Sprite object.

In the example flash movie at the beginning of this post you will notice that all the shapes are simple. That’s because everything is being redrawn every frame with only lines and no fill. That’s right, EVERYTHING is made in code. Nothing was drawn by hand.
If you want your game, or whatever, to have a little more character then that example movie, then you will probably want to associate hand made Sprites with your Body Definitions.

In the “Hello World” example, they use Sprites to display their objects. You could leave them invisible too if you really wanted. Either way they will still be accounted for in the calculations.

On to something very important. What is a Shape Definition!? We have 3 types of shape definition and they all extend the base b2ShapeDef class.

First we have the b2BoxDef class. The b2BoxDef has 4 important properties:
1.) Extents - this is a vector that essentially goes from one corner of the box to the exact center. In other words, half the width and hight. (box is a rectangle)
2.) Density - in the collision equations we use density * area = mass
A density of 0 (zero) or null will make the object static and it will never move in the case of a collision or gravity.
3.) Friction - this is used to calculate the friction between 2 objects… you should keep it between 0.0 and 1.0
4.) Restitution - this is the bounciness of the object. Should probably also stay between 0.0 and 1.0

The b2CircleDef has only one differences in it’s properties. Instead of Extents it has Radius, which is easy to remember.
The b2PolyDef has an array of (max 8) vertices instead of Extents or Radius. These vertices are just b2Vec2 vector objects.

Now Adding a bunch of objects to our world should be easy:

var bodyDef:b2BodyDef;
var boxDef:b2BoxDef;
var circleDef:b2CircleDef;

// Add ground body
bodyDef = new b2BodyDef();
boxDef = new b2BoxDef();
boxDef.extents.Set(1000, 100);
boxDef.friction = 0.3;
/*Notice that the ground object has no density like the later
definitions.  That’s because it is static and we don’t want it
effected by any forces.*/

bodyDef.position.Set(320, 400);
bodyDef.AddShape(boxDef);

// Add sprite to body userData
/*We have a Sprite object in the library called PhysGround.  Here
we are associating that with our body definition.*/

bodyDef.userData = new PhysGround();
bodyDef.userData.width = boxDef.extents.x * 2;
bodyDef.userData.height = boxDef.extents.y * 2;
addChild(bodyDef.userData);
m_world.CreateBody(bodyDef);

// Add some objects
for (var i:int = 1; i < 20; i++){
        /*We are going to re-use the same bodyDef from before.
        It doesn’t matter now, because it’s already been copied and stored
        in our world object.*/

        bodyDef = new b2BodyDef();
        // Box
        if (Math.random() < 0.5){
                boxDef = new b2BoxDef();
                boxDef.extents.Set(Math.random() * 15 + 10, Math.random() * 15 + 10);
                boxDef.density = 1.0;
                boxDef.friction = 0.5;
                boxDef.restitution = 0.2;
                bodyDef.AddShape(boxDef);
                /*We have a Sprite object in the library called PhysBox.*/
                bodyDef.userData = new PhysBox();
                bodyDef.userData.width = boxDef.extents.x * 2;
                bodyDef.userData.height = boxDef.extents.y * 2;
        }
        // Circle
        else {
                circleDef = new b2CircleDef();
                circleDef.radius = Math.random() * 15 + 10;
                circleDef.density = 1.0;
                circleDef.friction = 0.5;
                circleDef.restitution = 0.2
                bodyDef.AddShape(circleDef);
                /*We have a Sprite object in the library called PhysCircle.*/
                bodyDef.userData = new PhysCircle();
                bodyDef.userData.width = circleDef.radius * 2;
                bodyDef.userData.height = circleDef.radius * 2;
        }
        bodyDef.position.x = Math.random() * 400 + 120;
        bodyDef.position.y = Math.random() * 100 + 50;
        m_world.CreateBody(bodyDef);
        addChild(bodyDef.userData);
}

That’s great isn’t it? It’s really not that hard to add a whole bunch of objects to your world. You should know that the Step() function that we added earlier will only take care of moving and rotating our body definitions. If we have sprites to represent those definitions then we need to update them manually… they made the code for that easy and you can copy and paste it almost exactly into every one of your projects.
We just have to rewrite our Update function from before:

public function Update(e:Event):void{

        m_world.Step(m_timeStep, m_iterations);

        // Go through body list and update sprite positions/rotations
        for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next){
                if (bb.m_userData is Sprite){
                        bb.m_userData.x = bb.m_position.x;
                        bb.m_userData.y = bb.m_position.y;
                        bb.m_userData.rotation = bb.m_rotation * (180/Math.PI);
                }
        }/*This is an extreemly clever way to do this, and I suggest you copy it exactly in your own projects.*/

}

That’s it for now. We have objects in a world that can collide with each other and are affected by gravity. There is still a lot more to talk about, but I am just walking you through the “Hello World” first. We still need to cover Joints, Pulleys, Gears, Compound Shapes, Forced rotation (like cars tires), and a lot more… I doubt I will be able to cover all these topics anytime soon, but I will definitely write more tutorials on this physics engine in the future.

You can download my copy of the “Hello World” example project with all of my comments included (there is almost no commenting in the original).

Download Hello World w/ comments.

You can get all of the library files needed for Box2DFlash at their site. It’s free.

Credits:
Box2D - Erin Catto ( http://gphysics.com/ )
Box2DFlashAS3 - Matthew Bush (Flash ActionScript 3.0 port of Erin Catto’s work)

Tags: , , , , ,

Related Posts

13 Responses to “Physics in ActionScript 3: Box2DFlashAS3”

  1. Weese Says:

    Okay….I’m just gonna be real honest and let you know I don’t understand any of this. Just thought you should know Paul. On a fun note, you’re examples are a lot of fun to play with!

  2. Paul Says:

    Well this isn’t really for beginners Weese. I need to teach you how to animate something without ActionScript before I try and teach you Physics.
    I agree though, the example is a lot of fun to play with.

  3. §ean Says:

    Paul… I think your example is addictive to play with. I just spent like 30 minutes playing with all of the examples. Awesome!

  4. VQ Says:

    Joints! Pulleys! Gears you say?!? Compound Shapes! Forced rotation! I can barely contain my excitement!

  5. Paul Says:

    It seems that I was writing about Box2DFlash v1.4.3 and they are coming out with v2.0.0 very soon. So I might hold off on doing any more tutorials on this engine untill the new version comes out and I see what has changed.

  6. ClickPopMedia » Blog Archive » Cool Games made with Box2DFlash Says:

    [...] writing my introduction tutorial to Erin Catto’s Box2D AS3 physics engine port, I found out that I was writing about version [...]

  7. adam Says:

    Deadly!
    I can’t stop playing with this.

    …am I in…the future?

  8. Sasha Cohen Says:

    Hey!…Thanks for the nice read, keep up the interesting posts..what a nice Sunday . Sasha Cohen

  9. ClickPopMedia » Blog Archive » Box2DFlash v2.0.0 Released! Says:

    [...] I’ve been looking forward to this release since I found out about it while making a tutorial for the previous release (v1.4.3) about a month ago. Some of the major changes/additions to this [...]

  10. Ali Momeni Says:

    hello paul,
    thanks for the great work.
    when i try to run your helloworld examples, i get a bunch of errors like the ones below;
    i put your helloworld examples files right were the original Box2DFlash HelloWorld example was, i.e. there’s a folder called “Box2D” next to it with all the .as files that are needed.

    any idea what my problem is?

    —–the errors—–

    1046: Type was not found or was not a compile-time constant: b2BoxDef.

  11. charlie Says:

    *jaw drops* WOW - thanks Paul, thats great fun causing mayhem and throwing things around, feels just like being a child again :)

  12. Jack Says:

    Awesome. This example has been very helpful. Is there any chance you could update this tutorial for Box2D 2.0?
    Thanks.

  13. ClickPopMedia » Blog Archive » Specific changes to Box2DFlash “Hello World” example. Says:

    [...] talked about the basics of Box2DFlash v1.4.3 in my Introductory tutorial. I showed how to create your world and how to introduce simple bodies into that world. With the [...]

Comment