Creating box2d collision shapes for flash

Andreas Löw
Creating box2d collision shapes for flash
Last update: More than 3 months ago

Learn how to create collision shapes for box2d's flash/as3 port.

  • Creating the box2d collision shapes using PhysicsEditor
  • Setting up box2d for flash

Full source code to this example project is available on GitHub.

This is a short tutorial how to create collision shapes for box2d's flash/as3 port. In this tutorial I assume that you already managed to set up box2d and that you have some basic knowledge about it.

Creating the box2d collision shapes using PhysicsEditor

First select your exporter as Box2D Actionscript (FLASH) . Next drag your shapes (which you need in the form of png files) onto PhysicsEditor's left panel.

PhysicsEditor prepared for Flash / AS3 and box2d

The next step is to create the box2d collision polygons. You can do this either by hand using the add polygon tool, or the Automated Shape-Tracer .

Using the Automated Shape-Tracer

Automated Shape-Tracer is the simplest way to create a polygon shape. PhysicsEditor traces the transparency of a shape and creates a polygon. You can adjust parameters e.g. how accurate a polygon should be.

PhysicsEditor: Using the Automated Shape-Tracer

In the bottom left corner you see the number of vertexes that the output polygon will have. You need to find a reasonable amount here. On the one hand the shape should cover the shape good enough - on the other hand too many vertexes will consume a lot of cpu power during simulation.

Trace using Tolerance=1.0 PhysicsEditor: Trace using Tolerance=1.0

Results in 37 vertexes with a nearly perfect match. But this is way too much.

Trace with Tolerance=4.0 PhysicsEditor: Trace with Tolerance=4.0

Results in 12 vertexes - which still gives an acceptable match while keeping CPU requirements low.

You can always adjust the parameters manually if you need to.

Other parameters in the Automated Shape-Tracer are the alpha threshold which allows you to ignore semi transparent pixels while tracing.

If you have shapes which are separated by transparency you need to trace the shape several times. Click on the part of the image you want to trace.

Adding and editing polygons manually

As described above adding polygons is done using the add polygon button. This gives you a triangle which you can drag and enhance by adding vertexes.

You can drag vertexes by dragging them with the mouse.

Add vertexes by double clicking somewhere near a line between two vertexes. Remove vertexes by double clicking the vertex you want to remove.

PhysicsEditor: create collision shapes manually

Exporting data

If you are satisfied with your shapes export them using the Publish button. In our case it will create an ActionScript source file which you can import into flash.

Setting up box2d for flash

Let's now do the flash integration. Lets get started with the imports - including box2d, several flash classes and not to forget our physics data file:

// import stuff
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.getDefinitionByName;
	
// import box2d
import Box2D.Dynamics.Joints.*;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

// import the sprite data
import PhysicsData;

Now setup our main class, including a box2d world b2World with a gravity vector pointing down. And initialize the physics data object which keeps the shapes:

public class Main extends Sprite {

public var nextSprite:Number=10;

// create an object containing the shape data
public var physicsData:PhysicsData = new PhysicsData();

// create the box2d world, set up gravity
public var world:b2World=new b2World(new b2Vec2(0,10.0),true);

In the constructor of the class we set up a single sprite as static body b2_staticBody which will be the floor. To accomplish that we need to drag the bitmap from the library and create a Bitmap object from it. This is done within the first 2 lines.

The next thing to do is to take the physics body we created and connect it with the bitmap object. This is simply done by calling physicsData.createBody("floor",world,b2Body.b2_staticBody,bitmap) which takes the name of the object ("floor"), the b2World object ("world"), the body type (b2_staticBody) and our bitmap.

After creating the body we set a position and rotation. We need to divide the coordinates by the ptm_ratio we set in PhysicsEditor.

The last steps are to add the floor bitmap to the scene and to add an event listener - we need this one to simulate the world and to update the sprites and bitmaps to match the position of the physics shapes which box2d calculates for us.

public function Main():void {

    // Grab the bitmap from the compiled resources
    var artClass:Class = getDefinitionByName("floor") as Class;

    // Creat a display object to add to the stage
    var bitmap:Bitmap = new Bitmap(new artClass(0, 0), "auto", true);

    // create a physics body from the physics data structure
    var body:b2Body=physicsData.createBody("floor",
                                           world,
                                           b2Body.b2_staticBody,
                                           bitmap);
        
    // set the position of the sprite
    body.SetPositionAndAngle(
                new b2Vec2(0,337/physicsData.ptm_ratio), 0);
        
    // add the sprite to the scene
    addChild(bitmap);

    // add an event listener to update sprite's from
    // physics data
    addEventListener(Event.ENTER_FRAME, update, false, 0, true);
}

The next function adds random sprites from the library to the physics world - this time as dynamic objects (b2_dynamicBody). This means that they are completely controlled by the physics simulation.

The main part of the function is the same as setting up the floor sprite above.

// this function adds new sprites to the scene
public function addNewSprites():void {

    // only add sprites every 30th frame
    nextSprite--;
    if(nextSprite > 0)
    {
        return;
    }
    nextSprite = 30;

    // names of the items / sprites we use
    var items:Array=["hamburger",
                     "drink",
                     "icecream",
                     "icecream2",
                     "icecream3"];
        
    // choose a random object
    var name:String=items[Math.floor(Math.random()*items.length)];
        
    // Grab the bitmap from the compiled resources
    var artClass:Class = getDefinitionByName(name) as Class;

    // Creat a display object to add to the stage
    var bitmap:Bitmap = new Bitmap(new artClass(0, 0), "auto", true);
    
    // create a physics body from the physics data structure
    var body:b2Body=physicsData.createBody(name,
                                           world,
                                           b2Body.b2_dynamicBody,
                                           bitmap);
        
    // set a random start position
    body.SetPositionAndAngle(new b2Vec2(Math.random()*14,-2), 0);
        
    // add the sprite to the scene
    addChild(bitmap);
}

Last is update which is called for every frame. First we need to step the world which runs the box2d simulation. Then we add some new sprites - with the function above.

The loop iterates over all bodies, takes their user data pointer and casts it back to Bitmap. We now set the position and rotation copying the values from the box2d simulation. We need to multiply the coordinates with ptm_ratio to convert them back from box2d's internal meter representation to pixels.

// this function runs the world simulation
// and adjusts the sprites according to the positions
// of the objects in the simulation
public function update(e : Event):void {
    // step the world
    world.Step(1 / 30, 10, 10);
    
    world.ClearForces();
    
    // add new sprites to the world
    addNewSprites();

    // update the sprites from the physics data
    var Body:b2Body = world.GetBodyList();
    for ( ; Body; Body = Body.GetNext()) {
        if (Body.GetUserData() is Bitmap) {
            
            // get the user date value from the body
            var bitmap:Bitmap=Body.GetUserData() as Bitmap;
            
            // extract the position and set the sprite to it
            bitmap.x=Body.GetPosition().x*physicsData.ptm_ratio;
            bitmap.y=Body.GetPosition().y*physicsData.ptm_ratio;
            
            // set the rotation of the sprite
            bitmap.rotation = Body.GetAngle() * (180/Math.PI);
        }
    }
}

That's it

Well - that's all. You can download the complete source with everything you need.