Talking about Actionscript 3, Box2D, Flash, iOS and Starling.
One Box2D feature which is really underestimated is the debug draw. When I started blogging about Box2D I wrote a post about debug draw, but recently when I tried to render debug draw in Starling – which shouldn’t be possible since Starling does not use flash.display.Sprite
class – I googled a bit for it and found some workarounds that really scared me.
So, at first, here is how you can override the classic debug draw routine.
The example is taken from the post “creation of a Box2D hook like the one seen on iOS Mikey Hooks game” with highlighted lines to add.
Basically we create a custom debug class and override the orignal one:
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.Event; import Box2D.Dynamics.*; import Box2D.Collision.Shapes.*; import Box2D.Common.Math.*; import Box2D.Dynamics.Joints.*; public class Main extends Sprite { private var world:b2World=new b2World(new b2Vec2(0,10),true); private var worldScale:Number=30; private var hero:b2Body; private var distanceJoint:b2DistanceJoint; private var isHooked:Boolean=false; private var customDebug=new CustomDebug(); public function Main() { addBox(320,480,640,20,b2Body.b2_staticBody); for (var i:Number=1; i<=12; i++) { addBox(Math.random()*600+20,Math.random()*300,Math.random()*30+15,Math.random()*30+15,b2Body.b2_staticBody); } hero=addBox(320,460,20,20,b2Body.b2_dynamicBody); addEventListener(Event.ENTER_FRAME,update); stage.addEventListener(MouseEvent.MOUSE_DOWN,fireHook); stage.addEventListener(MouseEvent.MOUSE_UP,releaseHook); debugDraw(); } private function fireHook(e:MouseEvent):void { if (distanceJoint) { world.DestroyJoint(distanceJoint); } world.QueryPoint(queryCallback,new b2Vec2(mouseX/worldScale,mouseY/worldScale)); } private function queryCallback(fixture:b2Fixture):Boolean { var touchedBody:b2Body=fixture.GetBody(); if (touchedBody.GetType()==b2Body.b2_staticBody) { var distanceJointDef:b2DistanceJointDef=new b2DistanceJointDef(); distanceJointDef.Initialize(hero,touchedBody,hero.GetWorldCenter(),new b2Vec2(mouseX/worldScale,mouseY/worldScale)); distanceJointDef.collideConnected=true; distanceJoint=world.CreateJoint(distanceJointDef) as b2DistanceJoint; isHooked=true; } return false; } private function releaseHook(e:MouseEvent):void { if (distanceJoint) { world.DestroyJoint(distanceJoint); } } private function manageHook():void{ if (isHooked) { hero.SetAwake(true) distanceJoint.SetLength(distanceJoint.GetLength()*0.99); } } private function addBox(pX:Number,pY:Number,w:Number,h:Number,bodyType:Number):b2Body { var bodyDef:b2BodyDef=new b2BodyDef(); bodyDef.position.Set(pX/worldScale,pY/worldScale); bodyDef.type=bodyType; var polygonShape:b2PolygonShape=new b2PolygonShape(); polygonShape.SetAsBox(w/2/worldScale,h/2/worldScale); var fixtureDef:b2FixtureDef=new b2FixtureDef(); fixtureDef.shape=polygonShape; fixtureDef.density=1; fixtureDef.restitution=0.4; fixtureDef.friction=0.5; var body:b2Body=world.CreateBody(bodyDef); body.CreateFixture(fixtureDef); return body; } private function debugDraw():void { var debugSprite:Sprite=new Sprite(); addChild(debugSprite); customDebug.SetSprite(debugSprite); customDebug.SetDrawScale(worldScale); customDebug.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit); customDebug.SetFillAlpha(0.5); world.SetDebugDraw(customDebug); } private function update(e:Event):void { world.Step(1/30, 10, 10); manageHook(); world.ClearForces(); world.DrawDebugData(); } } }
And this is CustomDebug
class:
package { import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Contacts.*; import Box2D.Dynamics.*; import Box2D.Common.Math.*; import Box2D.Common.*; import flash.display.Sprite; public class CustomDebug extends b2DebugDraw { override public function DrawSolidPolygon(vertices:Vector.<b2Vec2>, vertexCount:int, color:b2Color):void { color = new b2Color(Math.random(),Math.random(),Math.random()) var m_sprite:Sprite=this.GetSprite(); var m_lineThickness:Number=this.GetLineThickness(); var m_drawScale:Number=this.GetDrawScale(); var m_alpha:Number=this.GetAlpha(); var m_fillAlpha:Number=this.GetFillAlpha(); m_sprite.graphics.lineStyle(m_lineThickness, color.color, m_alpha); m_sprite.graphics.moveTo(vertices[0].x * m_drawScale, vertices[0].y * m_drawScale); m_sprite.graphics.beginFill(color.color, m_fillAlpha); for (var i:int = 1; i < vertexCount; i++) { m_sprite.graphics.lineTo(vertices[i].x * m_drawScale, vertices[i].y * m_drawScale); } m_sprite.graphics.lineTo(vertices[0].x * m_drawScale, vertices[0].y * m_drawScale); m_sprite.graphics.endFill(); } override public function DrawSegment(p1:b2Vec2, p2:b2Vec2, color:b2Color):void { color = new b2Color(Math.random(),Math.random(),Math.random()) var m_sprite:Sprite=this.GetSprite(); var m_lineThickness:Number=this.GetLineThickness(); var m_drawScale:Number=this.GetDrawScale(); var m_alpha:Number=this.GetAlpha();; m_sprite.graphics.lineStyle(m_lineThickness, color.color, m_alpha); m_sprite.graphics.moveTo(p1.x * m_drawScale, p1.y * m_drawScale); m_sprite.graphics.lineTo(p2.x * m_drawScale, p2.y * m_drawScale); } } }
The result I wanted to give is some kind of psychedelic effect just to show you something, anyway you got the point:
You should know how to play: click and hold your mouse over a static body to create a hook and rewind it, release mouse button to destroy the hook. Try to swing like a tarzan geek.
And this is a video taken directly from my iPhone, how you can see it works, although it’s dropping a bit my frame rate, but since it’s just a debug, it does not matter:
And… yes, I am making a game out of it. Hoping not to get sued by Spiderman…
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.