box2d

box2d

Box2D

This is a blog dedicated to Box2D alchemy port for Flash.

First steps in Box2D for Flash Actionscript 3.0

TutorialsPosted by Admin Fri, June 17, 2011 11:06:00

Box2D is a physics library created by Eric Catto for C++. Being very fast and covering all aspects of 2D space, it has become very popular, mainly being used in 2D games, and it is ported to almost existing programming languages. Flash (and therefore Actionscript) could not stay out as one of the most popular frameworks for creating games for the web.

Until now, there are two kinds of Box2D versions for flash, the native version created by and a version created with the help of Adobe Alchemy by . The latter is the subject of this tutorial.

Box2D library, although it’s very fast for physics calculations, it has the drawback for the most of the flash developers of its weird (to the usual flash coding style) syntax which is mainly because it’s ported directly from C++ and the various considerations made for creating robust methods with not too many arguments. Another drawback for the flash users is that Box2D is using real life measure units like kilograms and meters when most flash developers are used to the flash units, i.e. pixels.

We will start using Box2D by creating a simple animation, which is feed by physics. But first let’s setup the Box2D library. You can download the latest from Jesse’s repository located here . There are various folders but the only one we need is the one called Box2DAS. Copy this folder to the project directory of yours. I’m currently using FlashDevelop, a free and open source Actionscript IDE that can be downloaded from here.

Besides having Box2DAS folder in our project directory, we also have to add its component (swc) file to the library of your project. It’s the Box2D.swc file located in the Box2DAS folder. In FlashDevelop, right click on it and select Add to Library. Now we are ready compile and run a Actionscript project that supports Box2D.

The first animation created with Box2D is a falling ball on a steady ground. The only force existing will be gravity. A 300x300 pixels window is used. The full project can be downloaded from here.

The source code is the following:

package

{

import Box2DAS.Dynamics.b2DebugDraw;

import flash.events.Event;

import Box2DAS.Dynamics.b2World;

import Box2DAS.Common.b2Base;

import Box2DAS.Common.V2;

import Box2DAS.Dynamics.b2Body;

import Box2DAS.Common.b2Def;

import flash.display.Sprite;

/**

* ...

* @author giorgos

*/

public class FallingBall extends Sprite

{

private var myWorld:b2World;

private var ground:b2Body;

private var circle:b2Body;

private var debug:b2DebugDraw = new b2DebugDraw();

public function FallingBall():void

{

initializeBox2D();

createGround();

createBall();

addChild(debug);

addEventListener(Event.ENTER_FRAME,worldStep);

}

private function createBall() : void

{

b2Def.body.type = b2Body.b2_dynamicBody;

b2Def.circle.m_radius = 30/30;

b2Def.fixture.restitution = 0.5;

b2Def.fixture.shape = b2Def.circle;

b2Def.body.position.v2 = new V2(100/30,100/30);

circle = myWorld.CreateBody(b2Def.body);

circle.CreateFixture(b2Def.fixture);

}

private function worldStep(event : Event) : void

{

myWorld.Step(1/60, 10,10);

myWorld.ClearForces();

debug.graphics.clear();

debug.world = myWorld;

debug.scale = 30;

debug.Draw();

}

private function initializeBox2D() : void

{

b2Base.initialize();

myWorld = new b2World(new V2(0,10),true);

}

private function createGround() : void

{

b2Def.body.type = b2Body.b2_staticBody;

b2Def.polygon.SetAsBox(150 / 30, 5 / 30);

b2Def.fixture.shape = b2Def.polygon;

ground = new b2Body(myWorld);

ground.CreateFixture(b2Def.fixture);

ground.SetTransform(new V2(150/30,300/30), 0);

}

}

}

The majority of the Box2D classes and methods have the b2 prefix.

The 1st thing we have to do is to define the world

private var myWorld:b2World;

, where all the objects will exist in,

and initialize it

b2Base.initialize();

myWorld = new b2World(new V2(0,10),true);

The two arguments of the World object are its gravity and a boolean value stating whether it allows objects to sleep or not. V2 class is nothing more than a 2d vector class properly defined in box2D (including appropriate methods) in order to use it in various physics concepts such as velocity, forces like gravity etc. Allowing objects to sleep means not to take into account (for various calculations) objects that are not affected by forces such as gravity or those created by collision with other objects. It is advisable to let it to true in the beginning, for performance reasons, until you become more comfortable with using box2D.

The next step is to create the bodies of the objects that exist in our world. The first object we create is the following:

b2Def.body.type = b2Body.b2_staticBody;

b2Def.polygon.SetAsBox(150 / 30, 5 / 30);

b2Def.fixture.shape = b2Def.polygon;

ground = new b2Body(myWorld);

ground.CreateFixture(b2Def.fixture);

ground.SetTransform(new V2(150/30,300/30), 0);

To create a physics object in Box2D, we have to create its body and attach to it a shape and a fixture (which is a bunch of material properties like friction, restitution and density). We use b2Def class to create static objects that can be reused for performance. We can first set up the type of the body. There are three available types: static, dynamic and kinematic. We want here to create a box to be the ground of the environment. So, we use the static type, which creates a body that is immovable and only affects other objects, it is not affected itself by other objects or forces.

Subsequently, we create a shape; in this case a polygon. The simplest way to create a polygon is by setting is as a simple box of 4 edges and to do that we have only to pass 2 arguments for its length and width. Here come two tricky parts, regarding their size. The first one, which only applies for creating boxes like this, is that we have to pass the half size of the sides of the box and not their normal sizes. So, if we want a box of 30 x 20 we need to declare a box of 15 x 10.

The second tricky part explains why we divide the lengths with 30. As already stated in the beginning, box2D uses real life measure units like meters. In Flash, however, we use pixels. Thus we have to convert it to pixels using a simple scaling factor. Choosing the number 30 here we mean that 30 pixels will refer to 1 meter. The appropriate choose of the scaling factor has to do with the kind of world we want to simulate. Box2D works best with objects from 0.1m (like a coin) to 10 meters (like a bus). Statics objects however can be up to 50 meters. For the most of the cases a scaling factor like 30 is the most appropriate and this is advised to be used for the beginning.

Afterwards we set that this box will be the shape of the fixture that we will attach to the body of the ground object. We subsequently create the body, instantiating it by passing the world it belongs to. Finally we attach to it the object containing its material properties, i.e. its fixture.

In the end we reposition the ground box to the low part of our window. In this setup, we use a 300 x 300 px window. The reference point for a box2D box is its centre. So, we have to place its centre to the point 150,300 of the window in order to be in the lower part of it.

The next step is to create a dynamic body, which hence can be affected by gravity.

b2Def.body.type = b2Body.b2_dynamicBody;

b2Def.circle.m_radius = 30/30;

b2Def.fixture.restitution = 0.5;

b2Def.fixture.shape = b2Def.circle;

b2Def.body.position.v2 = new V2(100/30,100/30);

circle = myWorld.CreateBody(b2Def.body);

circle.CreateFixture(b2Def.fixture);

The procedure is similar to creating a box. We first, of course, set the type to be dynamic, otherwise the object would stay immovable. Instead of now use a polygon we use a circle shape and the only thing we need to do with it, is to define its radius size.

The additional thing here is that we change one of its material properties. So, we change its fixture. The restitution property has to do with how bouncy an object will be and takes values greater or equal to 0 up to 1, where 0 is not to be bouncy at all and 1 is to have a perfectly elastic collision, i.e. its velocity will be reflected. Here we set up an average restitution in order to see some effect upon colliding with the ground.

The next thing we see is the following declaration:

private var debug:b2DebugDraw = new b2DebugDraw();

Box2D variables are reflecting some physics properties. They are nothing more than numbers that are keeping calculated all the time according to some rules that respect some physics laws. In order to visualize these physics results we have to attach to these numbers some graphics, whose values will be calculated from box2D.

We usually create some graphics for our games and we attach on them some box2D properties in order to have a nice physics respected simulation. The box2D alchemy port has already implemented a whole class of vector graphics that can be used to visualize the physics numbers of box2D and easily debug the simulations we are creating. This is why we use a variable of b2DebugDraw type; to see some shapes in Flash, whose size and position is calculated by box2D.

The final step is to set in movement all the things we created so far. This is done by setting box2D to calculate all physics properties all the time and update them. This can be done in flash either using a timer or using the event triggered on every frame, like in our example:

myWorld.Step(1/60, 10,10);

myWorld.ClearForces();

debug.graphics.clear();

debug.world = myWorld;

debug.scale = 30;

debug.Draw();

There are basic two steps that we need to make, set up properly the world step and call its appropriate method to clear the forces for this frame and reactivate them in the next one. For defining the step of the world, we need to pass 3 arguments. The physics equations are simulated at discrete points of time. In game loops we have a flip movement of the movement in the screen. For the definitions we did so far for our objects, an appropriate step is one of at least 60Hz or 1/60 seconds. The time step is easier to be static, as a variable time step is really harder to debug. The next two values are the solvers of the constraint, regarding the velocity and the position constraints respectively. In order to solve all collisions and set the objects that are colliding properly, it is needed to iterate though them some times until their collisions are solved. The more times we iterate though them the more accurate is the result but also it can be slower. This is upon the result we would like to have and whether we can sacrifice quality for speed.

The final 4 lines have to do with setting up our graphics. We have to clear them in every frame in order to be drawn to their new positions calculated by box2D. The b2DebugDraw object has to know also its world it belongs to. We must also not forget out scaling factor, in order to convert the box2D meters to pixels that flash is using for measuring its graphics.


Fill in only if you are not real





The following XHTML tags are allowed: <b>, <br/>, <em>, <i>, <strong>, <u>. CSS styles and Javascript are not permitted.