Platform game basics using Box2D

Read all posts about "" game

I wrote about Box2D Flash version about a year ago, then I published Playing with Box2DFlashAS3 and Create a Flash game like Totem Destroyer as examples covering what you can do with this library.

But I was really impressed by a thread on TriquiTips submitted by Hawdon called Box2DAs3 For Beginners! (read steps 1 and 2) that in my opinion deserves to be posted on this blog, to reach a wider public… because I know there is a lot of people looking for AS3 and Box2D and platform tutorials… and the prototype made by Hawdon merges them all this way:

Left-right to move and up to jump

This is the source code with some comments

package {
	// Imports some things into the movie.
	import flash.display.Sprite;
	import flash.events.*;
	import flash.events.KeyboardEvent;
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;

	public class Box2d extends Sprite {

		public function Box2d() {

			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);

			var worldAABB:b2AABB = new b2AABB();//Creates a new world
			worldAABB.lowerBound.Set(-100.0, -100.0);//Sets the lower bloundaries of the world (If a shape goes outside this it will freez)
			worldAABB.upperBound.Set(100.0, 100.0);//Sets the upper bloundaries of the world (If a shape goes outside this it will freez)

			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);//Sets gravity. First number is Y and second is x
			var doSleep:Boolean = true;//If the shapes are allowed to sleep. (Stop simulating)
			m_world = new b2World(worldAABB, gravity, doSleep);//Sets everything together to make a Box2d World


			CreateBox(275, 375, 600, 50, true, new Ground());//Ground

			CreateCircle(250, 100, 50, false, new Circle());//Ball

			CreateHero(200, 300);//Player

			CreateBox(500, 302, 200, 100, true, new Ground());//Static Box on right side




			/* following code makes some stacks of blocks*/
			for (var x:int = 1; x<4; x++) {
				for (var i:int = 1; i<11; i++) {
					CreateBox(((300+(20*x))-(.25*i)), (365-(20*i)), 20, 20, false, new Box());
				}
			}
		}
		/*
		          I personaly think its MUCh easier to put the code into functions,
		         because then you dont need to type it again, and again, and again. And it works just fine with function like createCircle and createBox.
		          And when its time to start making levels, you will have a lot less typing to do when you can just type in the function.
		          */





		/* 
		      Following Function Creates the Hero 
		      CreateHero(X Posision, Y Posision, Width of Hero, Height of Hero)
		      */
		public function CreateHero(x:Number, y:Number, width:Number = 20, height:Number = 20) {
			bodyDef = new b2BodyDef();
			bodyDef.position.x = (x)/physScale;
			bodyDef.position.y = (y)/physScale;
			boxDef = new b2PolygonDef();
			boxDef.SetAsBox(GetRealWH(20), GetRealWH(20));
			boxDef.density = 1.0;//Because the density is at higher then 0 it moves.
			boxDef.friction = 0.3;
			boxDef.restitution = 0.2;
			bodyDef.userData = new PlayerBox();
			bodyDef.userData.name = "Player";
			bodyDef.userData.width = physScale * 2 * GetRealWH(width);
			bodyDef.userData.height = physScale * 2 * GetRealWH(height);
			body = m_world.CreateBody(bodyDef);
			body.SetBullet(true);//Tells flash to treat it like a bullet (Continuous collision detection.)
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
			bodyDef.userData.body = body;//This is the only way I know that u can get a specific body from the World.
			//If you have a better idea, tell me!
			addChild(bodyDef.userData);

		}
		/* 
		      Following function Creates a Circle 
		      CreateCircle(X posision, Y Posision, Width/Height of ball, Is the ball static (Inmoveable), The movieclip you want to be shown as the circle (Example: new Circle())
		      */
		public function CreateCircle(x:Number, y:Number, width:Number, static:Boolean, Cover) {
			/* Following Code creates a circle */
			bodyDef = new b2BodyDef();
			bodyDef.position.x = x/physScale;
			bodyDef.position.y = y/physScale;
			circleDef = new b2CircleDef();//Defines circleDef as a new b2CircleDef
			circleDef.radius = GetRealWH(width);//Sets the radius of the ball
			circleDef.density = 1.0;
			circleDef.friction = 0.3;
			circleDef.restitution = 0.2;
			bodyDef.userData = Cover;//sets userData to a new Circle (See Library)
			bodyDef.userData.width = 30 * 2 * GetRealWH(width);//Sets width and height. Third Number is the same as the radius.
			bodyDef.userData.height = 30 * 2 * GetRealWH(width);
			trace(bodyDef.userData.height);
			body = m_world.CreateBody(bodyDef);
			body.CreateShape(circleDef);
			body.SetMassFromShapes();
			addChild(bodyDef.userData);

		}
		/*
		      Following function creates a box 
		      CreateBox(X posision, Y Posision, Width, Height, Is the box static (Inmoveable), The movieclip you want to be shown as the box (Example: new Box())
		      */
		public function CreateBox(x:Number, y:Number, width:Number, height:Number, static:Boolean, Cover) {
			/* Creates the static box on the right side of the screen*/
			bodyDef = new b2BodyDef();
			bodyDef.position.x = (x)/physScale;
			bodyDef.position.y = (y)/physScale;
			boxDef = new b2PolygonDef();
			boxDef.SetAsBox(GetRealWH(width), GetRealWH(height));
			if (static) {
				boxDef.density = 0.0;
			}
			else {
				boxDef.density = 1.0;
			}
			boxDef.friction = 0.3;
			boxDef.restitution = 0.4;
			bodyDef.userData = Cover;
			bodyDef.userData.width = physScale * 2 * GetRealWH(width);
			bodyDef.userData.height = physScale * 2 * GetRealWH(height);
			bodyDef.isBullet = true;//This tells flash to treat all boxes like bullets. This is CPU consuming with a lot of boxes.
			//But the hit test is WAY better when you use this.
			body = m_world.CreateBody(bodyDef);
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
			addChild(bodyDef.userData);

		}
		/*
		      I hade to make this function because I noticed that
		      the width and height of the shapes were 2 times to large 
		      even to I divided it by physScale.
		      This is because Box2d when doing width and height only takes from the center out.
		      For Example: if I use this SetAsBox(100/physScale, 100/physScale)
		      I will get a box that is 200x200 because the 100/physScale is the distance from the
		      center of the box to the top  or the sides.
		      
		      I made this function because I like using the numbers I usualy use in flash 
		      when making games.
		      */
		public function GetRealWH(Num:Number) {
			return Num / physScale / 2;
		}
		/*
		      Following functions a controls when any aroow key is pressed.
		      */
		public var Left:Boolean = false;
		public var Right:Boolean = false;
		public var Up:Boolean = false;
		public function KeyDown(e:KeyboardEvent) {
			trace(e.keyCode);
			var TheChild = getChildByName("Player");
			var Body = TheChild.body;
			switch (e.keyCode) {
				case 37 ://Left
					Left = true;
					break;
				case 38 ://Up
					Up = true;
					break;
				case 39 ://Right
					Right = true;
					break;

			}
		}
		public function KeyUp(e:KeyboardEvent) {
			trace(e.keyCode);
			var TheChild = getChildByName("Player");
			var Body = TheChild.body;
			switch (e.keyCode) {
				case 37 ://Left
					Left = false;
					break;
				case 38 ://Up
					Up = false;
					break;
				case 39 ://Right
					Right = false;
					break;

			}
		}
		/* Following function gets the body from a cordinate (x, y)*/
		public function GetBodyAtPoint(px:Number, py:Number, includeStatic:Boolean = false) {
			// Make a small box.
			var px2 = px/physScale;
			var py2 = py/physScale;
			var PointVec:b2Vec2 = new b2Vec2();
			PointVec.Set(px2, py2);
			var aabb:b2AABB = new b2AABB();
			aabb.lowerBound.Set(px2 - 0.001, py2 - 0.001);
			aabb.upperBound.Set(px2 + 0.001, py2 + 0.001);

			// Query the world for overlapping shapes.
			var k_maxCount:int = 10;
			var shapes:Array = new Array();
			var count:int = m_world.Query(aabb, shapes, k_maxCount);
			var body:b2Body = null;
			for (var i:int = 0; i < count; ++i) {
				if (shapes[i].m_body.IsStatic() == false || includeStatic) {
					var tShape:b2Shape = shapes[i] as b2Shape;
					var inside:Boolean = tShape.TestPoint(tShape.m_body.GetXForm(), PointVec);
					if (inside) {
						body = tShape.m_body;
						break;
					}
				}
			}
			return body;
		}
		public function Update(e:Event):void {
			/*Following code down to line 252 Makes the Player move left, right and jump*/
			var TheChild = getChildByName("Player");//Getts a child named Box
			var Body = TheChild.body;//Get the var body from the child.
			if (Left) {//If Left Arrow is down
				Body.WakeUp();//Wakes the body up if its sleeping
				Body.m_linearVelocity.x = -3;//Adds to the linearVelocity of the box.
			}
			if (Right) {//If right arrow is down
				Body.WakeUp();//Wakes the body up if its sleeping
				Body.m_linearVelocity.x = 3;//Adds to the linearVelocity of the box.
			}
			if (Up) {
				if (Body.GetLinearVelocity().y > -1) {//Stops player from sometimes jumpping higher then suppose to
					/*
					               I have made 3 hit points.
					               */
					var Hit = GetBodyAtPoint(TheChild.x, TheChild.y+(TheChild.height/2+2), true);//Under
					var Hit1 = GetBodyAtPoint(TheChild.x-(TheChild.width/2)+2, TheChild.y+(TheChild.height/2+2), true);//Down-Left
					var Hit2 = GetBodyAtPoint(TheChild.x+(TheChild.width/2)-2, TheChild.y+(TheChild.height/2+2), true);//Down-Right
					if (Hit != null && Hit.m_userData != TheChild) {
						Body.ApplyImpulse(new b2Vec2(0.0, -3.0), Body.GetWorldCenter());//Applys and impuls to the player. (Makes it jump)
					}
					else if (Hit1 != null && Hit1.m_userData != TheChild || Hit2 != null && Hit2.m_userData != TheChild) {

						Body.ApplyImpulse(new b2Vec2(0.0, -3.0), Body.GetWorldCenter());
					}//Applys and impuls to the player. (Makes it jump)
				}
			}
		};
		Body.m_sweep.a = 0;//This is what stops the player from rotating
		/*
		         But because its only called once a frame it will allow the player to rotate a little.
		         Which makes it more realistic.
		         
		         */

		m_world.Step(m_timeStep, m_iterations);//This runns the Box2D World

		//Body.m_sweep.a = 0; //If you wanned to take the tiny movement away you could move this code here. 
		// The follwoing code rotates, sets the x and y cordinates of the movieclips the player sees.
		for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {//Makes a for loop scanning all the bodys in the World
			if (bb.m_userData is Sprite) {//Checks if bb.m_userData is a spirit (Movieclip)
				bb.m_userData.x = bb.GetPosition().x * physScale;//Changes the x
				bb.m_userData.y = bb.GetPosition().y * physScale;//Changes the y
				bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);//Changes the rotation
			}
		}
	}
	/* Vars used in creating shapes */
	public var body:b2Body;
	public var bodyDef:b2BodyDef;
	public var boxDef:b2PolygonDef;
	public var circleDef:b2CircleDef;

	public var m_world:b2World;
	public var m_iterations:int = 15;
	public var physScale:Number = 30;
	public var m_timeStep:Number = 1.0/physScale;

}
}

I have to say I am quite impressed about this work and I am porting my platform engine using Box2D, and release some Box2D tutorials if this post gets a good feedback.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers