Platform game basics using Box2D

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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.

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (26 votes, average: 4.54 out of 5)
Loading ... Loading ...
If you found this post useful, please consider a small donation.
» Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.

27 Responses to “Platform game basics using Box2D”

  1. Daniel Rodriguez on October 26th, 2008 8:39 pm

    Really nice, Box2D makes a realistic game, more than the tile engine.

  2. Hawdon on October 26th, 2008 8:57 pm

    Got to say, didn’t excpect you to post it on the blog…
    But thanks!

    I’m, too, very intérested to hear what ppl think.
    If there is a lot of good feedback I might too post some more tutorials.

  3. Josh of Cubicle Ninjas on October 26th, 2008 11:49 pm

    I caught this on Triqui and somehow messed up during the tutorial. So glad to have a reminder to try it once again! :)

  4. Josh of Cubicle Ninjas on October 26th, 2008 11:52 pm

    “I have to say I am quite impressed about this work and I am porting my platform engine using Box2D…”

    YAY! Made my week.

  5. Dude on October 27th, 2008 12:12 am

    It would be much better if you finish your engine first….I would really apreciate it :P

  6. Scarybug on October 27th, 2008 5:12 am

    You should check out sideroller.com, and the world creation kit [http://www.sideroller.com/wck/]

  7. anlik on October 27th, 2008 8:03 am

    I like your website and I come here every day,please go on the BOX2D engine tutorial.

    非常期待你的box 2d教程,也非常尊敬你,吼吼,请一定加油,我是一名FLASH GAME DEVELOPER,一直在关注你的网站,非常非常非常期待你的物理引擎教程

  8. mrcool on October 27th, 2008 8:47 am

    awesome!!!

  9. Robin on October 27th, 2008 10:45 am

    Wow! Just awesome! I’m going to try to combine the previous platform engine with this one :D

  10. ptz on October 27th, 2008 11:58 am

    AWESOME! make more tutorials about box2d!!!

  11. Karuka on October 27th, 2008 3:42 pm

    Yay! I got the ball up the wall!

  12. Marius on October 27th, 2008 5:13 pm

    “…and I am porting my platform engine using Box2D…”

    That would be awsome!

  13. oliver_l1 on October 27th, 2008 8:22 pm

    awesome! box2d rocks!

  14. mark on October 28th, 2008 1:37 am

    box2d is awesome!!! because of this im going to learn as3!! please make more!!!!!

  15. PGN on October 30th, 2008 12:36 am

    Thanks for another great tutorial! Box2D is awesome. More Box2D please :D !

  16. Pippo on November 27th, 2008 7:16 pm

    what we could do for the scrolling?

  17. malte on January 14th, 2009 10:04 pm

    i get alot of errors when i try to compile your example with the latest box3d code. Is there a newer Verison availabe? Did you alot of customizations to the Box2D Classes?

  18. sega on February 12th, 2009 3:23 pm

    Yeah, it’s not working for me either, but I only get one error on line 1.

    “5006: An ActionScript file can not have more than one externally visible definition: Box2d, body”

  19. afk on February 17th, 2009 5:04 pm

    why making an tutorial it it’s full of errors ? :E

    yeah, sure, i can make changes to use for my project, but what if i have no time ? and for very beginners?

  20. Ivan on March 24th, 2009 8:01 am

    This tutorial it’s great, I was looking for something like this over the internet for a long time. However this example doens’t show how to scroll smothly the world like this game made with box2dAS3

    http://www.huesforalice.com/project/box2d_tinger

    Does anyone know some tutorial that could explain that?

    Thank you

  21. jfdurand on July 24th, 2009 2:29 am

    I really like your work and constant progression. Go on! You do great!

    Just for you to know for linking bodies and graphics, i use this myself (the actor part):

    http://www.box2d.org/wiki/index.php?title=Linking_graphics_to_bodies_in_Box2D_AS3

    Hope it helps you someway!

    JF

  22. raz on November 23rd, 2009 12:09 am

    Really good tutorial, but it seems to have a little bug: if you jump into the wall and keep the right arrow pressed, the hero stays stuck on the wall and does not fall as it should.

    Is there anyway to fix this?

    Thanks.

  23. Andrew on December 16th, 2009 4:42 am

    to make this scroll do you just do that like normal and extend your Box2D bounding area?

  24. Andrew on December 16th, 2009 5:05 pm

    since I guess that site went down this tutorial is really hard to follow. too many errors and with out the source I can’t figure them out!
    SOURCE PLZ

  25. danang on January 27th, 2010 4:18 am

    tanks for sharing tutorial

  26. Trent Sterling on February 4th, 2010 2:17 pm

    How do we keep our player object from bouncing?!

Leave a Reply




Trackbacks

  1. Christina Friel: ActionScripting and Design » Box2D: AS3 on March 13th, 2009 6:00 am
flash games company