Using Box2d to Create a Side Scrolling Game – Part 1: Intro and Setting Up Box2d

The purpose of these articles will be to make a basic side scrolling type game using Box2d to handle collision detection.

This article will show you how to set up a project with box2d, and start creating objects to be used in a side scrolling type game (such as Super Mario Brothers).

Tutorial Demo

Adding Box2d to Your Game Project

The first thing you need to do is create a new AS3 project in FlashDevelop (Project->New Project->AS3 Project) called ‘box2d_tut’.

Next, download Box2d for AS3 from: http://box2dflash.sourceforge.net/.

Inside the Box2d zip file there will be a ‘Source’ folder – with a folder named ‘Box2d’ inside it. Copy this into your project folder under the ‘src’ folder.

NOTE: There is also a folder called “Examples”, which includes some examples of using box2d, and the source files used to create them. You can learn a lot from these files, so it would be good to unzip them somewhere as well.

Now in FlashDevelop, you should see your src folder with the Box2D folder inside of it, with the file named “Main.as”.

I like to put my game code in it’s own folder, so right click on ‘src’, ‘Add->NewFolder’ and name the folder ‘Game’.

Right click on the Game folder, and go to ‘Add->New Class’ and name it ‘Game’.

Now open up your ‘Game.as’, and add in the following code:

Game.as

package Game 
{
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2Fixture;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	/**
	 * ...
	 * @author Chris Moeller
	 */
	public class Game 
	{
		public var stage:Stage;
		
		public const gravity:Number = 9.8; //gravity direction, positive is down in screen coordinates
		public const scale:Number = 30; //the scale the Box2d world will be compared to screen size
		
		public var world:b2World; //create the "physics world"
		
		public var hero_box:b2Body; //the object we'll use to control our "hero"/ main character
		
		public function Game(stage:Stage) 
		{
			this.stage = stage; //assign the main "stage" to a variable in "Game.as" so it has access to it, and can add any objects to the screen it needs to
			world = new b2World(new b2Vec2(0, gravity), true); //initialize the world; first parameter a 2d vector to represent the direction+magnitude of gravity (straight down and at 9.8m/s^2
			
			//add the "debug drawings" to the screen:
			var debug_sprite:Sprite = new Sprite(); //our debug sprite, where all of the physical objects can be drawn upon before we add graphics
			stage.addChild(debug_sprite);
			
			var debug_draw:b2DebugDraw = new b2DebugDraw();
			debug_draw.SetSprite(debug_sprite);
			debug_draw.SetDrawScale(scale);
			debug_draw.SetFlags(b2DebugDraw.e_shapeBit);
			world.SetDebugDraw(debug_draw);
			
			//create a static/unmoving box along the bottom to use as the ground
			CreateBox(0, stage.stageHeight - 50, stage.stageWidth, 50, false);
			
			//create your "hero" box to be used as your character later on
			hero_box = CreateBox(200, 100, 50, 50, true, 1);
			
			//create a couple "blocks" on the screen
			CreateBox(200, stage.stageHeight - 50 * 4, 50, 50, false);
			CreateBox(350, stage.stageHeight - 50 * 4, 50, 50, false);
			CreateBox(400, stage.stageHeight - 50*4, 50, 50, false);
			
			stage.addEventListener(Event.ENTER_FRAME, RunGame); //main game loop which will perform calculation simulations each frame, and game processes
		}
		/*
		function used to create boxes quickly, without having to do all the box2d initializations each time
		*/
		public function CreateBox(x:Number, y:Number, width:Number, height:Number, is_dynamic:Boolean, density:Number=1):b2Body
		{
			//first tranfer all the pixel units into box2d units
			x = Con2B2D(x);
			y = Con2B2D(y);
			width = Con2B2D(width);
			height = Con2B2D(height);
			
			var box_body:b2BodyDef = new b2BodyDef();
			box_body.position.Set(x+width/2, y+height/2); //NOTE: box2d sets the position of the center of an object, not the top left like normal. So we have to add the middle (width/2, height/2) to the position to position where we actually want to have it
			
			if (is_dynamic)
				box_body.type = b2Body.b2_dynamicBody;
			
			var box_poly_shape:b2PolygonShape = new b2PolygonShape();
			box_poly_shape.SetAsBox(width / 2, height / 2);
			var box_fixture:b2FixtureDef = new b2FixtureDef();
			box_fixture.shape = box_poly_shape;
			box_fixture.density = density;
			var world_box_body:b2Body = world.CreateBody(box_body);
			world_box_body.CreateFixture(box_fixture);
			
			return world_box_body;
		}
		/*
			Main Loop: Used to run the physics simulation each frame, as well as any game processes
		*/
		public function RunGame(e:Event):void
		{
			world.Step(1/30,10,10); //performs a time step in the box2d simulation
			world.ClearForces(); //used to clear the forces after performing the time step
			world.DrawDebugData(); //draw the updated debug draw/graphics before adding out graphics
			
			//lets set the hero box to moving forward, as running along the ground
			if(hero_box.GetLinearVelocity().x< Con2B2D(60))
				hero_box.ApplyImpulse(new b2Vec2(Con2B2D(40), 0), hero_box.GetWorldCenter());
			
			//if the hero is below the bottom of the screen, bring him back to the original positon
			if (ConFromB2D(hero_box.GetPosition().y) > stage.stageHeight)
				hero_box.SetPosition(new b2Vec2(Con2B2D(200), Con2B2D(100)));
		}
		/*
		Helper function - used to convert normal pixel coordinates into Box2d coodinates (which are set at 1/scale or 1/30 right now)
		*/
		public function Con2B2D(num:Number):Number
		{
			return num / scale;
		}
		/*
		Helper function - used to convert box2d coordinates into pixels
		*/
		public function ConFromB2D(num:Number):Number
		{
			return num * scale;
		}
	}
}

I commented the code pretty thoroughly, but there are some important points to be aware of when using Box2d.

Line 23: Box2d needs to have a ‘scaling factor’. It is apparently optimized for objects within a certain size in meters(.1m to 10m)- so the standard is a scale of 30 to get most normal flash object sizes down to that size.

For instance our default screen is 640×480 pixels so using a scale of 1, box2d sees the objects in that many meters, or .4Miles wide, by .3 miles tall!
Dividing this by 30, instead we get 21m x 16m (64x48ft) as our largest size to fit on screen.
Alternatively, 1px is 1/30m= .03m.

So we can see that scaling by 10 gets us objects that are 1.5x to 2x larger than Box2d’s “ideal” units, but at the same time potentially 1/3 smaller with objects only 1px in dimension.

For this game, it will mainly be made up of moving blocks 50x50pixels, which comes down to 1.6m, which is between the .1-10m that Box2d is supposed to work best with.

So in other words – box2d is designed to work within a certain scale, which causes us to need to scale EVERY number we use into “Box2D coordinates”.

It’s a hassle, and you’ll find that forgetting to convert anywhere will cause huge problems- because an object will be 30x the distance away then you think it is.

Line 69: Box2d places objects according to their center, not their top left corner like in actionscript.
So you need to add 1/2 the width and the height to the x and y position to position it according to it’s top left corner.

Line 104, 111 These two functions are used to be able to quickly convert between box2d coordinates and pixels. It’s also good to use functions to remind yourself that you need to convert every unit.

The last thing we need to do to see our box2d world is create a new ‘Game’ object from our Main.as, and pass it the stage to allow it to add objects on screen.

Main.as

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import Game.Game;
	
	/**
	 * ...
	 * @author Chris Moeller
	 */
	public class Main extends Sprite 
	{
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			new Game(stage); //create a new game object and pass it the stage object
		}
	}
}

If you compile your program now (Ctrl+Enter), you’ll see your Box2d objects, and your “hero” object moving on screen due to the impulse applied to that object.

In the next section we’ll add keyboard input to allow our hero to move around, jump, and have some “automated” bad guys walking around.

Download the source Code and please leave me any comments or feedback you have.

Other Articles in this Series

Bookmark the permalink.

2 Comments

  1. Really helpful, looking forward to the rest of the series!

  2. I like this tutorial is very good. tahnks man.

Leave a Reply

Your email address will not be published. Required fields are marked *