Box2D 2.1a Tutorial – Part 1

Physics engines are arguably one of the most engaging elements in interactive media. Not only do they add visual realism but they also allow a greater interactive experience.
The Flash platform has a multitude of physics engine libraries available but the one I will be focusing on is Box2D 2.1a - arguably the most powerful and feature rich physics engine of them all.


A little background info: Box2D is the brainchild of Erin Catto, Blizzard‘s Principle Software Engineer. Box2D is in fact written in C++, but such is its popularity it spawned many ports with ActionScript 3 being no exception. In charge of the manual porting to ActionScript 3 has been BorisTheBrave who has kept up with Erin’s updates. With the release of 2.1 emerged a new port, created by Jesse Sternberg, who leveraged Alchemy to generate AS3 code from the C++ version. He has also made a framework WCK to allow developers to create Box2D objects by using the Flash IDE to layout the various elements.

However, for now, I will be focusing on BorisTheBrave’s port which you can download from here.

Box2D can be fairly intimidating to begin developing with due to its sheer scale so we are going to ease into it. I have based my following tutorial heavily on Box2D manual’s Hello World tutorial, the major changes being all the code examples are written in AS3 and a few minor creative liberties that I have taken. Make sure you are familiar with the following definitions from the Box2D manual:

  • shape: A 2D geometrical object, such as a circle or polygon.
  • rigid body: A chunk of matter that is so strong that the distance between any two bits of matter on the chunk is completely constant. They are hard like a diamond. In the following discussion we use body interchangeably with rigid body.
  • fixture: A fixture binds a shape to a body and adds material properties such as density, friction, and restitution.
  • world: A physics world is a collection of bodies, fixtures, and constraints that interact together. Box2D supports the creation of multiple worlds, but this is usually not necessary or desirable.

To help visualize the relationship between the classes I have created this chart:

Box2D 2.1a Chart

Lets start coding:

1. Create the world. The first parameter is a 2D vector that defines the world’s gravity. The second parameter is a Boolean to allow bodies to sleep. This is an optimization so that the physics engine does not needlessly process objects in the world that are not moving.

package
{
	import Box2D.Dynamics.b2World;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Dynamics.b2Fixture;
	import Box2D.Dynamics.b2FixtureDef;
	import flash.display.MovieClip;
	import Box2D.Dynamics.b2DebugDraw;
	import flash.display.Sprite;
	import flash.events.Event;

	public class HelloWorld extends MovieClip
	{

		private const PIXELS_TO_METRE:int = 30;
		private const SWF_HALF_WIDTH:int = 400;
		private const SWF_HEIGHT:int = 600;
		private var _world:b2World;

		public function HelloWorld()
		{

			_world = new b2World(new b2Vec2(0,10),true);

2. Create the ground box definition. In Box2D the units of measurement are in Metres. We specify a ratio of pixels to metres (this value is up to you). Additionally, the objects in Box2D have a origin that is in the centre of the object. Since the SWF in my example is 800×600 and the ground box will be 800 pixels wide to match,  I set the X position to half  that and convert to metres.

			var groundBodyDef:b2BodyDef= new b2BodyDef();

			groundBodyDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METRE,
                        SWF_HEIGHT/PIXELS_TO_METRE-20/PIXELS_TO_METRE);

3. Here we can see the factory design pattern being used to create the body.

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

4. Now we create our shape.

			var groundBox:b2PolygonShape = new b2PolygonShape();
			groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METRE,20/PIXELS_TO_METRE);

5. We can set various properties when we create the fixture.

			var groundFixtureDef:b2FixtureDef = new b2FixtureDef();
			groundFixtureDef.shape = groundBox;
			groundFixtureDef.density = 1;
			groundFixtureDef.friction = 1;
			groundBody.CreateFixture(groundFixtureDef);

The following code runs through steps 1-5 again as we make a small box to place in this world.

			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type = b2Body.b2_dynamicBody;
			bodyDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METRE,4);
			var body:b2Body = _world.CreateBody(bodyDef);

			var dynamicBox:b2PolygonShape = new b2PolygonShape();
			dynamicBox.SetAsBox(1,1);

			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.shape = dynamicBox;
			fixtureDef.density = 1;
			fixtureDef.friction = 0.3;

			body.CreateFixture(fixtureDef);

6. This part I added, you won’t find it on the HelloWorld tutorial from the Box2D tutorial. This piece of code allows us to see the world we have created rather than just trace statements.

			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(PIXELS_TO_METRE);
			debugDraw.SetLineThickness( 1.0);
			debugDraw.SetAlpha(1);
			debugDraw.SetFillAlpha(0.4);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
			_world.SetDebugDraw(debugDraw);

7. Now we need to give this world some life and let it run. An ENTER_FRAME event listener will do the job.

			addEventListener(Event.ENTER_FRAME, update);
		}

8. To update the world we call the step function. Step accepts three parameters. The first being the timestep. Box2D manual recommends 1/60 seconds. I find it best to set it to the SWF framerate , so in this case 1/30. The next two parameters are the velocityIterations and positionIteration with 10 being the suggested count for each. Fewer iterations boosts performances but comes at the cost of accuracy.

		public function update(e : Event):void
		{
			var timeStep:Number = 1 / 30;
			var velocityIterations:int = 6;
			var positionIterations:int = 2;

			_world.Step(timeStep,velocityIterations,positionIterations);

9. As of version 2.1 we must clear the forces.

			_world.ClearForces();

10. For drawing the debug data that we set earlier.

			_world.DrawDebugData();
		}

So that ends the first Box2D 2.1a tutorial. If you decide to start experimenting on your own and are checking out other code samples be careful of what version you are looking at. Pre 2.1 Box2D code examples will not compile without tweaking. Final code:

package
{
	import Box2D.Dynamics.b2World;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Dynamics.b2Fixture;
	import Box2D.Dynamics.b2FixtureDef;
	import flash.display.MovieClip;
	import Box2D.Dynamics.b2DebugDraw;
	import flash.display.Sprite;
	import flash.events.Event;

	public class HelloWorld extends MovieClip
	{
		private const PIXELS_TO_METRE:int = 30;
		private const SWF_HALF_WIDTH:int = 400;
		private const SWF_HEIGHT:int = 600;
		private var _world:b2World;

		public function HelloWorld()
		{
			_world = new b2World(new b2Vec2(0,10),true);

			var groundBodyDef:b2BodyDef= new b2BodyDef();
			groundBodyDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METRE,
                          SWF_HEIGHT/PIXELS_TO_METRE-20/PIXELS_TO_METRE);

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

			var groundBox:b2PolygonShape = new b2PolygonShape();
			groundBox.SetAsBox(SWF_HALF_WIDTH/PIXELS_TO_METRE,
                           20/PIXELS_TO_METRE);

			var groundFixtureDef:b2FixtureDef = new b2FixtureDef();
			groundFixtureDef.shape = groundBox;
			groundFixtureDef.density = 1;
			groundFixtureDef.friction = 1;
			groundBody.CreateFixture(groundFixtureDef);

			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type = b2Body.b2_dynamicBody;
			bodyDef.position.Set(SWF_HALF_WIDTH/PIXELS_TO_METRE,4);
			var body:b2Body = _world.CreateBody(bodyDef);

			var dynamicBox:b2PolygonShape = new b2PolygonShape();
			dynamicBox.SetAsBox(1,1);

			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			fixtureDef.shape = dynamicBox;
			fixtureDef.density = 1;
			fixtureDef.friction = 0.3;

			body.CreateFixture(fixtureDef);

			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(PIXELS_TO_METRE);
			debugDraw.SetLineThickness( 1.0);
			debugDraw.SetAlpha(1);
			debugDraw.SetFillAlpha(0.4);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
			_world.SetDebugDraw(debugDraw);

			addEventListener(Event.ENTER_FRAME, update);
		}

		public function update(e: Event):void
		{
			var timeStep:Number = 1 / 30;
			var velocityIterations:int = 6;
			var positionIterations:int = 2;

			_world.Step(timeStep,velocityIterations,positionIterations);
			_world.ClearForces();
			_world.DrawDebugData();
		}
	}
}
  • Pingback: Box2D 2.1a Tutorial part 3. Custom shapes and textures | Allan Bishop's Developer Blog

  • Cjboy1984

    So b2World will be automatically added to the stage or the movieclip in construction? I didn’t see any addChild() function in the sample code @@;

  • Cjboy1984

    Is the measurement of b2Vec2 Metres too?

  • http://twitter.com/AllanBishop Allan Bishop

    Yep. So the 10 in the b2Vec2 passed into the world constructor is an approximation of gravity (-9.8m/s/s)

  • http://twitter.com/AllanBishop Allan Bishop

    Nope, the b2World doesn’t extend Sprite so it doesn’t get added to anything (nor do we need to).

  • Cjboy1984

    And how do we see the b2box rectangle on the stage? Is it because b2DebugDraw?
    I checked out there aren’t any addChild in b2World class!

  • Cjboy1984

    I have another question: can I explain this word, fixture =
    any of various devices for holding parts in certain positions during welding, assembly, etc.

  • Anonymous

    yeah, we provide a debug draw sprite that is added to the HelloWorld movieclip which in turn is added to the stage. This sprite is then passed into the SetSprite function so that Box2D can store a reference to it and use it to draw on :)

  • Anonymous

    From the manual documentation: “A fixture is used to attach a shape to a body for collision detection. A fixture inherits its transform from its parent. Fixtures hold additional non-geometric data such as friction, collision filters, etc.”

  • Pingback: Box2D Flash 2.1 Hello World Falling Boxes | Lon (Alonzo) Hosford's Bitbox

  • Donotpostemail

    Thanks this helped clear up a lot with the new 2.1a changes.

    I put the example tutorial to work at http://www.lonhosford.com/lonblog/2010/10/27/box2d-flash-2-1-hello-world-falling-boxes/ and updated Todd Kerpelman’s video tutorial example.

  • Anonymous

    Glad to help :)

    Good work on your tutorial too. Nice to see a Box2D implementation with Flex.

  • Ivan

    Thanks for tutorial. It was helpfull for me.

  • Chris

    Hi Allan, thanks a lot for your nice tutorial! I am beginning to learn more about box2D thanks to you

  • Paresh Solanki

    Perfect One,

  • james

    Hey Alan,

    Thanks alot for these tutorials, just unpacked box2d 2.1a now and all the other stuff tutorials out there seem to cover the older build, so it’s great that someones done something to help us get started and beyond!

  • Sudarshan Badireddi

    thanks for a very nice tutorial ..

  • Sudarshan Badireddi

    Hi , I am not able to figure out from where the colors are being assigned to the respective bodies. ? pretty much noobish ..but please explain

  • Anonymous

    hey, the colours are being being assigned in the DrawDebugData() function in the b2World class. You can modify them if you want, but since it is just a debug draw mode there is no real point, and probably not a good idea as it is part of the Box2D source.

    Part 3 of these tutorials is where we start creating custom textures and assign them to the bodies http://blog.allanbishop.com/box2d-2-1a-tutorial-%e2%80%93-part-3-custom-textures-and-shapes/

  • Sacheras3

    I want to congratulate you for these tutorials are very good and I’m learning with them.
    I would like to ask you a favor and I hope not to be rude, you can put the codes in a file .zip is that for example the second tutorial I have not run me causes many problems. I appreciate if you can do.
    Thank and regards from Colombia.
    att Sacheras3

  • Anonymous

    Thanks, glad to see people are finding it useful :D . Yup, I have now uploaded the project file zip for the joints tutorial. You can find the download link at the bottom of the tutorial or you can download directly from this link http://blog.allanbishop.com/wp-content/uploads/2010/09/Box2DTutorialJoints.zip

  • Sacheras3

    Thanks for puts the code files on the second tutorial. Bye
    Regards
    att Sacheras3

  • Amit Rawat

    Very thanks Allen, for giving these nice tutorials…really appreciate your work on box2d…It is very useful for me. It’s really help me and make my days…even nights  (:

  • Etienne

    Thanks a lot, the tutorial i needed to get started with Box2D !

  • Pratik Chawke

    Thanks for the valuable tutorial………I need to about the elasticity of body…….If you are having any example on it then please post it……….

  • pratik

    Thanks for the valuable tutorial………I need to know about the
    elasticity of body…….If you are having any example on it then please
    post it…..

  • Anonymous

    Thanks :) What do you need to know about the elasticity of a a body? How to set it or..? Sounds like you want to take a look at the restitution when creating a b2Fixture

  • Shanecai

    very good basic tutorial! thanks for post

  • http://www.facebook.com/people/Sacher-Actionscript/100002130951381 Sacher Actionscript

    tanks allan for this great tutorial… 

  • 792103979

    为什么friction 不管用呢

  • Mischieviouspratik parikh

    If i am copying the code of hello world and publishing the swf in flash cs5.5 by using Box2DFlashAS3 2.1a folder its giving me a  error(1046: Type was not found or was not a compile-time constant: b2Fixture.)

    Does any one have any fix for this?
    Thanks in Advance.

  • Mischieviouspratik parikh

    Sorry My mistake, it comes if we keep lower version of flash, it atleast needs to have flash player 10 or the above version.

  • Tiago Galvão

    Very nice!  Exactly  what I was looking for in a Box2D tutorial to start using it with AS3. Thank you.

  • Dima332

    Thanks for good tutorials, I’m try it in Javascript + Canvas and it work.

  • Anonymous

    I should hopefully be starting up some Android development and trying out Box2D with it :)

  • Zyxstand

    length unit is arbitrary. if you want, you can think of it as meters or centimeters or feet – however your (imaginary) units are of the conversion ratio (pixels per meter or pixels per feet, etc)