Loop mp3 in Flash

Oke, here come my problem. I’m trying to create a sound looping engine in Flash, and because I don’t want files to be embedded in the FLA (in the library) I only can use MP3 as a sound file which I can load dynamically.

I didn’t know this, but mp3 has a silence at the end of the song, and sometimes also at the beginning of the song (and sometimes both).
Other file, files without compression like WAV, don’t have this problem.

I don’t want to get to deep into this problem, but if you’re interested in the problem and you need to read more about it: about gapless playback: Gapless playback and LAME tech FAQ.

I remember from AS2 the looping problem, but I hoped it was fixed in AS3.
So this is what I tried to do:

A colleague of mine (Boy Wonder) gave me a beat so I could go to work.

#1 – First try

First convert the beat from WAV to MP3: I used Audacity, an open source software for recording and editing sound.

Oke, the only thing I needed is to load the file (because it’s a local test, there is no loading) and hear if it worked:

// AS3
private var url:String = "MySound.mp3";
private var song:SoundChannel;
var request:URLRequest = new URLRequest(url);
var soundFactory:Sound = new Sound();
soundFactory.load(request);
song = soundFactory.play(0, int.MAX_VALUE); 

No, it didn’t loop correctly

#2 – Second try

Open the newly generated MP3, and there they are: the silence at the beginning and at the end of the song. I could use Audacity to remove it, but I use another program for that: mptrim.

mpTrim is a simple and easy to use MP3 editor.

  • mpTrim can trim MP3s – removing silent or unwanted parts.
  • mpTrim can adjust the volume of MP3s. Volume change can be manual or automatic (volume normalization).
  • mpTrim can fade-in/out MP3s (to fix abrupt beginning/ending).
  • mpTrim can clean-up MP3s and recover wasted disk space.
  • mpTrim keeps the music quality intact, no matter how many times you process an MP3, because it works directly in the MP3 format without having to decode/re-encode. That also makes it very fast.

mpTrim has an auto function for removing silent, so that’s very easy.

But after loading the new mp3 without silence, the hiccup was much smaller, but still there.

#3 – Third try (neeeh forget it)

The last try would be to fix it in code: I was thinking about a earlier starting a loop (0.02 second) but with a lot of tracks this would probably be very cpu intensive.
A quick search on the Internet, I couldn’t find a solution in code. It’s a bug in Flash and people that are more into sound then I am, are working hard to move Adobe to change some of the sound features in Flash: http://www.make-some-noise.info/

Conclusion

Because I have a hard head, and I need to make the same mistakes everyone makes….
But after all I have to conclude: It can’t be done, you will eventually get a hiccup in the loop.
It’s impossible to fix this problem.

So a dynamically loaded MP3 loops in flash will never work. The only way to get good loops is with WAV imported in the FLA (library) and use linkage

🙁

Document Class in AS3

A while back a read this post about the AS3 Pills #1 – Document class and it reminded me to write something about the “Document Class”. The title of this post is a little misleading: there is no “Document Class” in Actionscript 2 but this is probably the way you are searching for this problem.

A good explanation can be found on kirupa.com which has a ton of examples, explanations and tutorials!

But this is what it comes down to:

  1. create a folder with the name “Matthijs tutorials” (or use your own name, it’s not important)
  2. create in the folder “Matthijs tutorials”, another folder “source”
  3. save a flash file in the “source” folder: “documentClassTest.fla”
  4. now we start making packages: create a folder “nl”
  5. and save in folder “nl” a folder “matthijskamstra “
Folder structure (FlashDevelop)

Folder structure (FlashDevelop)

Goto Adobe Flash, and create a AS3 Flash file and save it in the source folder.

Fill in the document Class: nl.matthijskamstra.Main
(Flash will complain somewhat, you can ignore it for now…)

Document Class

Document Class

Create a new class in the folder matthijskamstra, default (at least the default Flashdevelop class) it will look something like this.
[as]
package nl.matthijskamstra {

/**
* @author Matthijs Kamstra aka [mck]
*/
public class Main {

public function Main () {

}

} // end class

} // end package
[/as]

If you would compile the .FLA now you will get an error (Compiler Errors):

Location: Main.as, Line 1
Description: 5000: The class ‘nl.matthijskamstra.Main’ must subclass ‘flash.display.MovieClip’ since it is linked to a library symbol of that type.

(if you compile using flex you will get this error)

Error #2023: Class Main$ must inherit from Sprite to link to the root.

The first time I got this error I couldn’t understand it, luckily I do now and the answer isn’t that difficult, but if you don’t know… 🙁

  • The class ‘nl.matthijskamstra.Main’ must subclass ‘flash.display.MovieClip’: the class that we just made needs to extend (be a subclass) of Movieclip (the root has a timeline)
  • since it is linked to a library symbol of that type: this is strange, this says that the class is linked to a library symbol. This what puzzled me the most: I (we) didn’t link this to a library item, we linked it to the document class. The Flex error helps more, but you can see the root as a very big movie (timeline) and let the error be the error.
  • Error #2023: Class Main$ must inherit from Sprite to link to the root.: why does flex say you need a to extend Sprite? Flex programmers don’t use the timeline and a Sprite is a Movieclip with just one frame.

So to sum things up: there are some stuff that you need to do with a document class that you don’t have to do to an other class:
First you need to extend it to Sprite or MovieClip. If you create more then one frame in the timeline you need to extend to MovieClip because MovieClip supports frames and Sprite doesn’t. I always choose to extend to MovieClip, because it covers all the bases… (a Sprite is a MovieClip with just one frame: a Sprite is not a MovieClip but a MovieClip is a Sprite)

Another error that seems to happen sometime (not if you use the default class from FlashDevelop)
Second a document class should be public (the constructor is always public).
A Constructor is a function or method that is called whenever the Class (in our case the document class) gets instantiated, it must never have a return type such as “void”

Don’t forget you need to import the MovieClip class: import flash.display.MovieClip; (see the error created by Flash)

So the Document Class looks now something like this:

[as]
package nl.matthijskamstra {

import flash.display.MovieClip;

/**
* @author Matthijs Kamstra aka [mck]
*/
public class Main extends MovieClip {

// constructor
public function Main () {
trace( “Main.Main” );
init ();
}

private function init ():void {
trace( “Main.init” );
}

} // end class

} // end package
[/as]

Export you Flash file and you will have two traces in you output panel

My default class looks similar, I add two group-imports:

	
import flash.display.*;
import flash.events.*;

with the “*” you import everything in that package (MovieClip, Sprite, etc)
because AS3 is event based, I import everything in the events-package

[as]
package nl.matthijskamstra {

import flash.display.*;
import flash.events.*;

/**
* @author Matthijs Kamstra aka [mck]
*/
public class Main extends MovieClip {

// constructor
public function Main () {
trace( “Main.Main” );
init ();
}

private function init ():void {
trace( “Main.init” );
}

} // end class

} // end package
[/as]

That’s it, I hope this clears the mystery called Document Class
Questions? You know where to place them!

Linkdump:
another post that I never finished, but it fits here…

Andrew Paul Simmons: Blog: ReferenceError: Error #1056: Caused by Declaring Stage Instances Private.

Ever got this error: ReferenceError: Error #1056: Cannot create property? No, then someone has explained it to you before you made this mistake.

Tiled background AS3

Sometimes you just need a pattern in the background that is fullscreen, of course you can use a big .PNG file but that is not always necessary.
You can use a pattern that you need to tile, I’ve written about this before: my post about tiled-background in Flash 8 AS2.
The code over there is based upon a tutorial (http://www.kirupa.com/developer/flash8/tiledbackground_flash8.htm)

And because kirupa is great they already have the answer:http://www.kirupa.com/forum/showthread.php?t=265953

But to put it next to each other:

AS2 example

For this example you need a bitmap in the library (right-click >> Linkage >> activate Export for ActionScript) with the Linkage Indentifier StripePattern_mc and this AS2 code placed in the root
[as]
import flash.display.BitmapData;
var backGroundBMP:BitmapData = BitmapData.loadBitmap(“StripePattern_mc”);
this.beginBitmapFill(backGroundBMP);
this.lineTo(Stage.width, 0);
this.lineTo(Stage.width, Stage.height);
this.lineTo(0, Stage.height);
this.lineTo(0, 0);
this.endFill();
[/as]

AS3 example

But in AS3 some things have changed. And for consistency I’m using StripePattern_mc although coding conventions will say it has to be StripePattern
[as]
var backGroundSprite:Sprite = new Sprite();
backGroundSprite.graphics.beginBitmapFill(new StripePattern_mc(0, 0));
backGroundSprite.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
backGroundSprite.graphics.endFill();
addChild(backGroundSprite);
[/as]

Besides the obvious changes, which I’m not going to explain (Stage.width vs stage.stageWidth, etc).

code line 2
BitmapData.loadBitmap is removed from AS3. There are no longer Linkage Identifiers and there is no longer attachMovie. Everything is created using the new operator.
And because a Bitmap(Data) needs two extra variables:
public function BitmapData(width:int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)

code line 3
drawRect is a new Graphic methode, but is does the same as the AS2 code part with lineTo, but shorter.

code line 5
and you need to add it to the displaylist (hmmm perhaps I need to explain this in a future post)

For this example I created a pattern with stripegenerator.com/ but any pattern will do.

Hello box2D – part 4

In my previous post I update the “Hello world” for box2D so that you can see something visual interesting.
You can find the original here: AS3: Hello Box2D.

Today I will post the same code but now how it should be.
Keeping the coding conventions in mind and making it easier to reuse code.

Still keeping in mind the original Hello world

[as]
package {

import flash.display.*;
import flash.events.*;
// Box2D Classes used in this “Hello world”
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

//[SWF(width=”640″, height=”480″, backgroundColor=”#000000″, frameRate=”60″)]
public class HelloWorld extends MovieClip {

public var world:b2World;
public var iterations:int = 10;
public var timeStep:Number = 1.0 / 60.0;
public var worldScale:Number = 30.0;

// to see what you have created
private var debugDraw:b2DebugDraw;
private var isDebugDrawing:Boolean = true; // change to false and there is no debugDraw

// constructor
public function HelloWorld() {
//trace( “HelloWorld.HelloWorld” );
init();
}

/**
* lets start building our “Hello world” box2D program
*/
private function init():void {
trace( “HelloWorld.init” );

createWorld();
creatingGroundBox();
creatingDynamicBody();

setupDebugDraw();

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

/**
* http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_World
*/
private function createWorld():void {
// Creat world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);

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

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

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

/**
* http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Ground_Box
*/
private function creatingGroundBox():void {
var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(0.0, -9.0);

var groundBody:b2Body = world.CreateBody(groundBodyDef);

var groundShapeDef:b2PolygonDef = new b2PolygonDef();
groundShapeDef.SetAsBox(50.0, 10.0);

groundBody.CreateShape(groundShapeDef);
}

/**
* http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Dynamic_Body
*/
private function creatingDynamicBody ():void {
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(10.0, 10.0);
var body:b2Body = world.CreateBody(bodyDef);

var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(1.0, 1.0);
shapeDef.density = 1.0;
shapeDef.friction = 0.3;
shapeDef.restitution = 0.8;
body.CreateShape(shapeDef);
body.SetMassFromShapes();

}

// extra to visualize
private function setupDebugDraw():void {
if(isDebugDrawing) {
debugDraw = new b2DebugDraw();
debugDraw.m_sprite = new Sprite();

addChild(debugDraw.m_sprite);

debugDraw.m_drawScale = 30;
debugDraw.m_fillAlpha = .25;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit ;
world.SetDebugDraw (debugDraw);
}
}

/**
* http://www.box2d.org/wiki/index.php?title=Manual/AS3#Simulating_the_World_.28of_Box2D.29
*/
public function onUpdateHandler(e:Event):void{
world.Step(timeStep, iterations);
}

} // end class

} // end package
[/as]

So all you need to do is CTRL+ENTER.

And you will have something like this:

You need to upgrade your Flash Player

You do not have the (correct) Flash plugin installed, or your browser does not support Javascript (you should enable it, perhaps?)

You need to download the Adobe Flash Player.

If you're sure you have the Flash plugin just ad
?detectflash=false
to the current url, to bypass the Flash-plugin detection.

Hello box2D – part 3

In my previous post I update the “Hello world” for box2D so that you can see something visual happening.
You can find the original here: AS3: Hello Box2D.

Today I will make it a little bit more attractive (remove trace).

First we change some settings to make it more fun to watch at!

The groundBodeDef (strange name for something that is the ceiling) is moved more down so you can see where the bodyDef is bouncing off.
[as]
//groundBodyDef.position.Set(0.0, -10.0); // [mck]: old code
groundBodyDef.position.Set(0.0, -9.0);
[/as]

The bodyDef is moved to the center and dropped a little higher
[as]
//bodyDef.position.Set(0.0, 4.0); // [mck]: old code
bodyDef.position.Set(10.0, 10.0);
[/as]

And the shapeDef is bouncy so that you can see what box2D can do:
[as]
shapeDef.restitution = 0.8; // [mck]: extra new code
[/as]

And delete the trace:
[as]
var position:b2Vec2 = body.GetPosition();
var angle:Number = body.GetAngle();
trace(position.x +’,’+ position.y +’,’+ angle);
[/as]

End result

The document class (HelloWorld.as) will look like this:

[as]
package {

import flash.display.*;
import flash.events.*;
// Box2D Classes used in this “Hello world”
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

// [SWF(width=”640″, height=”480″, backgroundColor=”#000000″, frameRate=”60″)]
public class HelloWorld extends Sprite {

private var body:b2Body;
private var world:b2World;

// constructor
public function HelloWorld() {
trace( “HelloWorld.HelloWorld” );

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_World
////////////////////////////////////////////////////////////////////////////////////////////////////
// Create world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);

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

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

// Construct a world object
// var world:b2World = new b2World(worldAABB, gravity, doSleep); // [mck]: old code
world = new b2World(worldAABB, gravity, doSleep);

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Ground_Box
////////////////////////////////////////////////////////////////////////////////////////////////////
var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(0.0, -10.0);

var groundBody:b2Body = world.CreateBody(groundBodyDef);

var groundShapeDef:b2PolygonDef = new b2PolygonDef();
groundShapeDef.SetAsBox(50.0, 10.0);

groundBody.CreateShape(groundShapeDef);

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Dynamic_Body
////////////////////////////////////////////////////////////////////////////////////////////////////
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(0.0, 4.0);
// var body:b2Body = world.CreateBody(bodyDef); // [mck]: old code
body = world.CreateBody(bodyDef);

var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(1.0, 1.0);
shapeDef.density = 1.0;
shapeDef.friction = 0.3;
body.CreateShape(shapeDef);
body.SetMassFromShapes();

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Debug_Drawing
////////////////////////////////////////////////////////////////////////////////////////////////////
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = new Sprite();

addChild(debugDraw.m_sprite);

debugDraw.m_drawScale = 30;
debugDraw.m_fillAlpha = .25;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit ;
world.SetDebugDraw (debugDraw);

//
addEventListener(Event.ENTER_FRAME, onUpdateHandler, false, 0, true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Simulating_the_World_.28of_Box2D.29
////////////////////////////////////////////////////////////////////////////////////////////////////
public function onUpdateHandler(e:Event):void{

var timeStep:Number = 1.0 / 60.0;
var iterations:Number = 10;

world.Step(timeStep, iterations);

}

} // end class

} // end package

[/as]

So all you need to do is CTRL+ENTER.

And you will have something like this:

You need to upgrade your Flash Player

You do not have the (correct) Flash plugin installed, or your browser does not support Javascript (you should enable it, perhaps?)

You need to download the Adobe Flash Player.

If you're sure you have the Flash plugin just ad
?detectflash=false
to the current url, to bypass the Flash-plugin detection.

Is this it? No, lets make it better.
Tomorrow more

Hello box2D – part 2

In my previous post I started with a “Hello world” for box2DFlash.
You can find the original here: AS3: Hello Box2D.

When you get it working you will not be satisfied: a black swf, with only a trace in the output panel.

Today I will make the “Hello world” more visible.

Debug_Drawing

This the preferred method of drawing these physics entities for debugging, rather than accessing the data directly. The reason is that much of the necessary data is internal and subject to change.

source: Debug_Drawing

Box2D has a debugDraw class that lets you see what you have built, they call it DebugDraw.
Take the code from yesterday and place this code before Simulating_the_World code.
[as]
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = new Sprite();

addChild(debugDraw.m_sprite);

debugDraw.m_drawScale = 30;
debugDraw.m_fillAlpha = .25;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit ;
world.SetDebugDraw (debugDraw);
[/as]

Thx Boy Wonder for pointing me to a little mistake in the part of the code: I forgot the last piece of code world.SetDebugDraw (debugDraw);. The class at the bottom of the page was correct!

So all you need to do is CTRL+ENTER.

Nice effect isn’t it? Almost? Well at least you see something although it’s not impressive…
Yeah, it’s isn’t much. Lets see how we can improve this.

Improve Debug_Drawing

The problem is that the debug window is created and executed 60 times, but because it is done in a for loop, you only see the end result (after 60 updates).
To see animation (if you follow the trace you see that something is moving) we need to update (visible) the data in dbgDraw more and we will use the frame rate to update it (yesterday set to 60 frames).
But for that there needs to be changed more than just a couple of lines

First we need to add some variables:
[as]
private var world:b2World;
private var body:b2Body;
[/as]
and change some related code:
[as]
// Construct a world object
// var world:b2World = new b2World(worldAABB, gravity, doSleep); // [mck]: old code
world = new b2World(worldAABB, gravity, doSleep);
[/as]
and
[as]
// var body:b2Body = world.CreateBody(bodyDef); // [mck]: old code
body = world.CreateBody(bodyDef);
[/as]

and remove the code add at Simulating_the_World with
[as]
addEventListener(Event.ENTER_FRAME, onUpdateHandler, false, 0, true);
[/as]

and add
[as]
////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Simulating_the_World_.28of_Box2D.29
////////////////////////////////////////////////////////////////////////////////////////////////////
public function onUpdateHandler(e:Event):void{

var timeStep:Number = 1.0 / 60.0;
var iterations:Number = 10;

world.Step(timeStep, iterations);

var position:b2Vec2 = body.GetPosition();
var angle:Number = body.GetAngle();
trace(position.x +’,’+ position.y +’,’+ angle);
}
[/as]

End result

The document class (HelloWorld.as) will look like this:

[as]
package {

import flash.display.*;
import flash.events.*;
// Box2D Classes used in this "Hello world"
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

// [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")]
public class HelloWorld3 extends Sprite {

private var body:b2Body;
private var world:b2World;

// constructor
public function HelloWorld() {
trace( "HelloWorld.HelloWorld" );

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_World
////////////////////////////////////////////////////////////////////////////////////////////////////
// Create world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);

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

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

// Construct a world object
// var world:b2World = new b2World(worldAABB, gravity, doSleep); // [mck]: old code
world = new b2World(worldAABB, gravity, doSleep);

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Ground_Box
////////////////////////////////////////////////////////////////////////////////////////////////////
var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(0.0, -10.0);

var groundBody:b2Body = world.CreateBody(groundBodyDef);

var groundShapeDef:b2PolygonDef = new b2PolygonDef();
groundShapeDef.SetAsBox(50.0, 10.0);

groundBody.CreateShape(groundShapeDef);

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Dynamic_Body
////////////////////////////////////////////////////////////////////////////////////////////////////
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(0.0, 4.0);
// var body:b2Body = world.CreateBody(bodyDef); // [mck]: old code
body = world.CreateBody(bodyDef);

var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(1.0, 1.0);
shapeDef.density = 1.0;
shapeDef.friction = 0.3;
body.CreateShape(shapeDef);
body.SetMassFromShapes();

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Debug_Drawing
////////////////////////////////////////////////////////////////////////////////////////////////////
var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = new Sprite();

addChild(debugDraw.m_sprite);

debugDraw.m_drawScale = 30;
debugDraw.m_fillAlpha = .25;
debugDraw.m_lineThickness = 1;
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit ;
world.SetDebugDraw (debugDraw);

//
addEventListener(Event.ENTER_FRAME, onUpdateHandler, false, 0, true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Simulating_the_World_.28of_Box2D.29
////////////////////////////////////////////////////////////////////////////////////////////////////
public function onUpdateHandler(e:Event):void{

var timeStep:Number = 1.0 / 60.0;
var iterations:Number = 10;

world.Step(timeStep, iterations);

var position:b2Vec2 = body.GetPosition();
var angle:Number = body.GetAngle();
trace(position.x +’,’+ position.y +’,’+ angle);
}

} // end class

} // end package
[/as]

So all you need to do is CTRL+ENTER.

Now we see something moving, and we have an endless stream of trace data.

It’s better, but there is more room for improvement…
tomorrow more.

Hello box2D – part 1

In programming the Hello world is probably the first you will ever make in a new language.
In the box2D wiki you can find a “Hello world” in box2DFlash style: AS3: Hello Box2D.

Easy as it should be … or is it?
This is not the “Hello world” I expected, so I’ll post one that helps you more on your way.

As irongleet mentions in the comments, this is not really a tutorial. There is already a tutorial on the page I mention above AS3: Hello Box2D. It’s not a bad tutorial, but you need to have some knowledge of AS3 to follow it and I personally don’t like the end result. So this is the first part of a series which will help you make more out of the previously mentioned tutorial. But I’m not going to copy past the tutorial written somewhere else and present it here. That’s why you should read the links to the source for more information. And the next Hello box2d – part 2 will have some more input from me.

Hello_Box2D

source: Hello_Box2D

Lets start with a Flash document width 640px, height 480px, backgroundColor=”#000000″ and a framerate 60.
And add a document class: HelloWorld.
Save this .fla (for example HelloWorldBox2d.fla).

Now get your favorite code-editor (I suggest FlashDevelop) and create that document class, name it HelloWorld.as:
[as]
package {

import flash.display.Sprite;
import flash.events.Event;
// Classes used in this example
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

public class HelloWorld extends Sprite{

// constructor
public function HelloWorld() {
trace( “HelloWorld.HelloWorld” );
}

} // end class

} // end package
[/as]
and save it next to the HelloWorldBox2d.fla.

You can see that I already add the import needed for Box2D.

The last thing you need to do is download the box2D classes: http://sourceforge.net/projects/box2dflash
Extract the zip file and copy the folder box2d next to the HelloWorldBox2d.fla and the HelloWorld.as

And now you are set…

Creating_a_World

Every Box2D program begins with the creation of a world object. This is the physics hub that manages memory, objects, and simulation.

source: Creating_a_World

The next piece of code can be placed in the constructor (public function HelloWorld() )
[as]
// Creat world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);

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

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

// Construct a world object
var world:b2World = new b2World(worldAABB, gravity, doSleep);
[/as]

Creating_a_Ground_Box

source: Creating_a_Ground_Box

[as]
var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(0.0, -10.0);

var groundBody:b2Body = world.CreateBody(groundBodyDef);

var groundShapeDef:b2PolygonDef = new b2PolygonDef();
groundShapeDef.SetAsBox(50.0, 10.0);

groundBody.CreateShape(groundShapeDef);
[/as]

Creating_a_Dynamic_Body

We can use the same technique to create a dynamic body. The main difference, besides dimensions, is that we must establish the dynamic body’s mass properties.

source: Creating_a_Dynamic_Body

[as]
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(0.0, 4.0);
var body:b2Body = world.CreateBody(bodyDef);

var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(1.0, 1.0);
shapeDef.density = 1.0;
shapeDef.friction = 0.3;
body.CreateShape(shapeDef);
body.SetMassFromShapes();
[/as]

Simulating_the_World

So we have initialized the ground box and a dynamic box. Now we are ready to set Newton loose to do his thing. We just have a couple more issues to consider.

source: Simulating_the_World
[as]
var timeStep:Number = 1.0 / 60.0;
var iterations:Number = 10;

for (var i:Number = 0; i < 60; ++i) { world.Step(timeStep, iterations); var position:b2Vec2 = body.GetPosition(); var angle:Number = body.GetAngle(); trace(position.x +','+ position.y +','+ angle); } [/as]

End result

The document class (HelloWorld.as) will look like this:

I didn’t wrote the code for this tutorial, so this is collection of code copy/paste from the original AS3: Hello Box2D tutorial. But I did, as many probably did, the original tutorial and I was a little disappointed at the end result… so my addition to the original tutorial can be read in the next part of this series (Hello box2d – part 2)

[as]
package {

import flash.display.Sprite;
// Box2D Classes used in this “Hello world”
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;

public class HelloWorld2 extends Sprite {

// constructor
public function HelloWorld() {
trace( “HelloWorld.HelloWorld” );

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_World
////////////////////////////////////////////////////////////////////////////////////////////////////
// Create world AABB
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);

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

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

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Ground_Box
////////////////////////////////////////////////////////////////////////////////////////////////////
var groundBodyDef:b2BodyDef = new b2BodyDef();
groundBodyDef.position.Set(0.0, -10.0);

var groundBody:b2Body = world.CreateBody(groundBodyDef);

var groundShapeDef:b2PolygonDef = new b2PolygonDef();
groundShapeDef.SetAsBox(50.0, 10.0);

groundBody.CreateShape(groundShapeDef);

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Creating_a_Dynamic_Body
////////////////////////////////////////////////////////////////////////////////////////////////////
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(0.0, 4.0);
var body:b2Body = world.CreateBody(bodyDef);

var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.SetAsBox(1.0, 1.0);
shapeDef.density = 1.0;
shapeDef.friction = 0.3;
body.CreateShape(shapeDef);
body.SetMassFromShapes();

////////////////////////////////////////////////////////////////////////////////////////////////////
// http://www.box2d.org/wiki/index.php?title=Manual/AS3#Simulating_the_World_.28of_Box2D.29
////////////////////////////////////////////////////////////////////////////////////////////////////
var timeStep:Number = 1.0 / 60.0;
var iterations:Number = 10;

for (var i:Number = 0; i < 60; ++i) { world.Step(timeStep, iterations); var position:b2Vec2 = body.GetPosition(); var angle:Number = body.GetAngle(); trace(position.x +','+ position.y +','+ angle); } } } // end class } // end package [/as] So all you need to do is CTRL+ENTER. Nice effect isn't it? No? Only some numbers in the output panel? Yeah I know that was not very useful... So next post will be a better/improved version of the Hello world box2D style >> read Hello box2d – part 2

Box2DFlashAS3 Refactored

If you are a Flex/Flash developer (and not familiar with another programming language), you will agree that the syntax for Box2DFlash is not following the AS3 coding conventions and seems funny.

Not that I’m so good at it (seem to have a lot of problem shaking the suffix “_mc”) but other people have the same problem: read this, this and this.

And one of them refactored the code, and not just someone: it done by John Lindquist (box2D user-name is pv3d).
John is one of the “Committer team” (?) of papervision3D and writes tutorials for papervision3D on pv3d.org.

You can find the code at http://code.google.com/p/box2dflash/ and John started working on tutorials (http://box2dflash.org/) but stopped after completing one… 🙁

You need to upgrade your Flash Player

You do not have the (correct) Flash plugin installed, or your browser does not support Javascript (you should enable it, perhaps?)

You need to download the Adobe Flash Player.

If you're sure you have the Flash plugin just ad
?detectflash=false
to the current url, to bypass the Flash-plugin detection.

I’ve took a quick look in the examples made by John, and I must confess that it seems more familiar/easier.
Conventions are you friend…

But what to do? Use the box2D port to AS3 from C++ or use the refactored one.
I’m using the original Box2DFlash AS3 2.0.1, not only for this reason (shaktool is one of two programmers responsible for the C++ to AS3 conversion and maintenance) but a lot of tutorials are based upon the original.

But I can’t wait for Box2DFlash AS3 2.0.2 and see what skatehead, shaktool and borisTheBrave have decided (I’m secretly cheering for John’s version!)

Box2DFlashAS3 documentation

In a previous post I started my journey into Flash physics by using Box2D.
And I “complained” about the documentation.

So I decided to create one for the boys & girls at the box2d Flash AS3 forum using ASDoc…..

Someone beat me to the punch: BorisTheBrave created a script to convert the current comment into ASDoc style comments and the result is posted here:
The unofficial Box2DFlashAS3 Documentation.

BorisTheBrave has made an update to the documentation: read more about that. I have really no idea what he did, I downloaded the files, but just over write existing files… why?
Anyway the Box2dAS3 documentation looks very nice, and that is the most important stuff he did!!

AS3 Flash Physics Engine Box2D

I was looking for a physics engine for Flash so I started looking for one… there are a lot of engines…
I won’t mention them all, there are enough people who did that already (here, here, here and here)

If the list is that big, how to choose?
Well I also want to use it with papervision3d so I googled on that and if someone checked out a couple of engines (this guy checked out 3).
And in one of my rss feeds there is a guy who builds games, and now it writing tutorials for box2d 😉

So I decided on box2d.

Box2D is an open source physics engine written primarily for games. As the name suggests, Box2D is a purely 2D engine. However, Box2D has grown beyond it’s humble box simulating roots, and can now handle convex polygons and other shapes coming soon.

Box2D is written in C++, but there is a port to as3: AS3 Flash Physics Engine Box2DFlashAS3 2.0.1.

You need to upgrade your Flash Player

You do not have the (correct) Flash plugin installed, or your browser does not support Javascript (you should enable it, perhaps?)

You need to download the Adobe Flash Player.

If you're sure you have the Flash plugin just ad
?detectflash=false
to the current url, to bypass the Flash-plugin detection.

Box2DFlashAS3 is an open source port of Erin Catto‘s powerful c++ physics library Box2D.

There is not a lot of information about Box2DFlashAS3 and tutorials are even harder to find.
So here some useful links:

Emanuele Feronato (an Italian PROgrammer) has written an extremely useful tutorial: box2d tutorial for the absolute beginners/. This one is a very good starting point!

I will write about the problems that I encounter with Box2D, I hope that will help you in your quest to understand box3DFlash.


Because I’m quite lazy, I didn’t mention all the as3 physics engines but you can: just make a comment about any engine and perhaps why you are working with that engine…