Understanding Box2D debug draw
When you are about to create a complex script with Box2D – or even a simple one, but that’s complex for your skills – I suggest to enable debug draw.
Debug draw will provide you everything you need in order to verify your script is working correctly, and once you are satisfied with the result, you can start attaching movieclips to skin the shapes.
So I am going to explain everything you need to know about debug draw, and probably something more.
The following movieclip is the HelloWorld.fla file you can find in the distribution package, with all movieclips removed and the debug draw enabled:
Let’ see how did I modify the script in order to enable debug draw… interesting lines range from line 21 to line 35
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 | package { import flash.display.Sprite; import flash.events.Event; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Common.Math.*; import Box2D.Dynamics.Joints.*; import flash.events.MouseEvent; public class HelloWorld extends Sprite { var body:b2Body; var mouseJoint:b2MouseJoint; public function HelloWorld() { addEventListener(Event.ENTER_FRAME, Update, false, 0, true); var worldAABB:b2AABB = new b2AABB(); worldAABB.lowerBound.Set(-100.0, -100.0); worldAABB.upperBound.Set(100.0, 100.0); var gravity:b2Vec2=new b2Vec2(0.0,10.0); var doSleep:Boolean=true; m_world=new b2World(worldAABB,gravity,doSleep); // debug draw start var m_sprite:Sprite; m_sprite = new Sprite(); addChild(m_sprite); var dbgDraw:b2DebugDraw = new b2DebugDraw(); var dbgSprite:Sprite = new Sprite(); m_sprite.addChild(dbgSprite); dbgDraw.m_sprite=m_sprite; dbgDraw.m_drawScale=30; dbgDraw.m_alpha = 1; dbgDraw.m_fillAlpha=0.5; dbgDraw.m_lineThickness=1; dbgDraw.m_drawFlags=b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit|b2DebugDraw.e_coreShapeBit|b2DebugDraw.e_aabbBit|b2DebugDraw.e_obbBit|b2DebugDraw.e_pairBit|b2DebugDraw.e_centerOfMassBit; m_world.SetDebugDraw(dbgDraw); // debug draw end var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(10, 12); boxDef = new b2PolygonDef(); boxDef.SetAsBox(30, 3); boxDef.friction=0.3; boxDef.density=0; body=m_world.CreateBody(bodyDef); body.CreateShape(boxDef); body.SetMassFromShapes(); for (var i:int = 1; i < 10; i++) { bodyDef = new b2BodyDef(); bodyDef.position.x=Math.random()*12+2; bodyDef.position.y=Math.random()*5; var rX:Number=Math.random()+0.5; var rY:Number=Math.random()+0.5; if (Math.random()<0.5) { boxDef = new b2PolygonDef(); boxDef.SetAsBox(rX, rY); boxDef.density=1.0; boxDef.friction=0.5; boxDef.restitution=0.2; body=m_world.CreateBody(bodyDef); body.CreateShape(boxDef); } else { circleDef = new b2CircleDef(); circleDef.radius=rX; circleDef.density=1.0; circleDef.friction=0.5; circleDef.restitution=0.2; body=m_world.CreateBody(bodyDef); body.CreateShape(circleDef); } body.SetMassFromShapes(); } stage.addEventListener(MouseEvent.MOUSE_DOWN, createMouse); stage.addEventListener(MouseEvent.MOUSE_UP, destroyMouse); } public function createMouse(evt:MouseEvent):void { var body:b2Body=GetBodyAtMouse(); if (body) { var mouseJointDef:b2MouseJointDef=new b2MouseJointDef ; mouseJointDef.body1=m_world.GetGroundBody(); mouseJointDef.body2=body; mouseJointDef.target.Set(mouseX/30, mouseY/30); mouseJointDef.maxForce=30000; mouseJointDef.timeStep=m_timeStep; mouseJoint=m_world.CreateJoint(mouseJointDef) as b2MouseJoint; } } public function destroyMouse(evt:MouseEvent):void { if (mouseJoint) { m_world.DestroyJoint(mouseJoint); mouseJoint=null; } } private var mousePVec:b2Vec2 = new b2Vec2(); public function GetBodyAtMouse(includeStatic:Boolean=false):b2Body { var mouseXWorldPhys = (mouseX)/30; var mouseYWorldPhys = (mouseY)/30; mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys); var aabb:b2AABB = new b2AABB(); aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001); aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001); 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].GetBody().IsStatic()==false||includeStatic) { var tShape:b2Shape=shapes[i] as b2Shape; var inside:Boolean=tShape.TestPoint(tShape.GetBody().GetXForm(),mousePVec); if (inside) { body=tShape.GetBody(); break; } } } return body; } public function Update(e:Event):void { m_world.Step(m_timeStep, m_iterations); if (mouseJoint) { var mouseXWorldPhys=mouseX/30; var mouseYWorldPhys=mouseY/30; var p2:b2Vec2=new b2Vec2(mouseXWorldPhys,mouseYWorldPhys); mouseJoint.SetTarget(p2); } } public var m_world:b2World; public var m_iterations:int=10; public var m_timeStep:Number=1.0/30.0; } } |
So now we are going to look at lines 22-34
22 23 24 25 26 27 28 29 30 31 32 33 34 | var m_sprite:Sprite; m_sprite = new Sprite(); addChild(m_sprite); var dbgDraw:b2DebugDraw = new b2DebugDraw(); var dbgSprite:Sprite = new Sprite(); m_sprite.addChild(dbgSprite); dbgDraw.m_sprite=m_sprite; dbgDraw.m_drawScale=30; dbgDraw.m_alpha = 1; dbgDraw.m_fillAlpha=0.5; dbgDraw.m_lineThickness=1; dbgDraw.m_drawFlags=b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit|b2DebugDraw.e_coreShapeBit|b2DebugDraw.e_aabbBit|b2DebugDraw.e_obbBit|b2DebugDraw.e_pairBit|b2DebugDraw.e_centerOfMassBit; m_world.SetDebugDraw(dbgDraw); |
Line 22: Declaring a new sprite called m_sprite
Line 23: Creating the sprite itself
Line 24: Adding the sprite to stage
Line 25: Declaring a new b2DebugDraw variable called dbgDraw
Line 26: Declaring and creating a new sprite called dbgSprite. This line acts like lines 22 and 23
Line 27: Adding this sprite to stage as a child of m_sprite
Line 28: Setting m_sprite as the sprite to use to render the world
You should not change anything until line 28
Now, it’s time to look at the ways to custom the debug draw. We will custom it by changing its attributes.
m_sprite as said, defines the sprite to be used for rendering
m_drawScale (line 29) sets the drawing scale of the rendering. As seen in Understanding pixels and meters with Box2D and how to select an object with mouse – part 2, one meter is equal to 30 pixels, so setting m_drawscale to 30 allows me to use pixel units.
This is how my movie looks like if I don’t set m_drawscale:

m_alpha (line 30) sets the alpha (from 0 to 1) for objects drawing color
m_fillAlpha (line 31) sets the alpha (from 0 to 1) for objects filling color
m_lineThickness (line 32) sets the thickness in pixels for objects drawing line
m_drawFlags (line 33) allows you to set some drawing flags. Before I explain every flag, let’s see how our movieclip will look like if I don’t set m_drawFlags

and now let’s see the flags you can assign, separed by a pipe |:
e_shapeBit: draws shapes
e_jointBit: draws joint connections
e_coreShapeBit: draws core (TOI) shapes
e_aabbBit: draws axis aligned bounding boxes
e_obbBit: draws oriented bounding boxes
e_pairBit: draws broad-phase pairs
e_centerOfMassBit: draws center of mass frame
The only thing you cannot change from here is the color of the objects: by default, Box2D assigns a green to static objects, a red to sleeping ones and a grey for moving ones.
You can change the colors editing b2World.as at lines 1060-1074 (line numbers may vary according to Box2D distribution)
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | for (s = b.GetShapeList(); s; s = s.m_next) { if (b.IsStatic()) { DrawShape(s, xf, new b2Color(0.5, 0.9, 0.5), core); } else if (b.IsSleeping()) { DrawShape(s, xf, new b2Color(0.5, 0.5, 0.9), core); } else { DrawShape(s, xf, new b2Color(0.9, 0.9, 0.9), core); } } |
You just have to change values inside b2Color with values from 0 to 1 where 1 is the 255 value we are used to deal with when working with colors.
We are almost ready to make our first Box2D game…
They can be easily customized to meet the unique requirements of your project.
6 Responses to “Understanding Box2D debug draw”
Leave a Reply
Trackbacks
-
Box2D: tutorial for the absolute beginners - step 2 : Emanuele Feronato on
January 29th, 2009 12:20 pm
[...] Lines 19-27: These lines handle the debug draw. Remember Box2D does not draw anything, it just calculates position, rotation and motion of every object in the world. So it’s up to you to attach real graphic assets to worl objects. Anyway, with some lines you can enable a debug draw mode that will help you during the creation of your script. For more information about debug draw read Understanding Box2D debug draw. [...]
- Citrus Engine released for free for learning
- My epic fail with ClickBank
- Get up to $100,000 for your next Flash game with Mochi GAME Developer Fund
- Create a dynamic content animated footer ad for your site in just 9 jQuery lines – 17 lines version
- Sell sitelocked version of your Flash games and even .fla sources to Free Online Games
- Protect your work from ActionScript code theft with SWF Protector
- Create a dynamic content animated footer ad for your site in just 9 jQuery lines
- Understanding Box2D’s one-way platforms, aka CLOUDS
- Triqui MochiAds Arcade plugin for WordPress upgraded to 1.2
- Box2D Flash game creation tutorial – part 2
- Create a Lightbox effect only with CSS - no javascript needed
- Flash game creation tutorial - part 1
- Create a Flash Racing Game Tutorial
- Flash game creation tutorial - part 2
- Make a Flash game like Flash Element Tower Defense - Part 2
- Flash game creation tutorial - part 3
- Make a Flash game like Flash Element Tower Defense - Part 1
- Create a flash draw game like Line Rider or others - part 1
- Triqui MochiAds Arcade plugin for WordPress official page
- Create a flash artillery game - step 1
- Flash game creation tutorial – part 5.2 (4.88/5)
- Create a flash artillery game – step 1 (4.79/5)
- Create a Flash Racing Game Tutorial (4.76/5)
- Create a survival horror game in Flash tutorial – part 1 (4.74/5)
- Create a flash artillery game – step 2 (4.74/5)
- Creation of a Flash arcade site using WordPress – step 2 (4.73/5)
- Flash game creation tutorial – part 1 (4.71/5)
- Flash game creation tutorial – part 2 (4.71/5)
- Create a flash draw game like Line Rider or others – part 1 (4.69/5)
- Creation of a platform game with Flash – step 2 (4.68/5)

(11 votes, average: 4.91 out of 5)



Great explanation, thanks! :D
viva italia :p
Great man, I like your all flash game tutorial, especially Box2D!!! Thanks your work!!!
Hi. Very interesting to know
Can you tell me where to change the color of joints?
I could not find that
However code fails at line 95
1046: Type was not found or was not a compile-time constant: b2Body.