Simulating a hook with Box2D
In a comment to Pumpkin Story prototype, a reader asked for a function to simulate a hook.
This can be quite easily done in some steps.
This first step will set a rule: you can only hook to a static body. Obviously it’s not a mandatory, rule, but just a gameplay one.
In this example, we’ll use the same script we saw at Box2D joints: Distance Joint with some modifications and the concept saw at Creating a sling with Box2D using joints when we must remove the hook.
This first part is simple, and will introduce us into the world of hooks.
Clicking and holding the mouse on a static object (the green one), we’ll create a joint between the centre of the ball and the mouse pointer.
Releasing the mouse will destroy the joint.
This is the script:
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 mouseJoint:b2MouseJoint; var mousePVec:b2Vec2 = new b2Vec2(); var bd:b2BodyDef; var the_circle:b2CircleDef = new b2CircleDef(); var circle:b2Body; var the_box:b2PolygonDef = new b2PolygonDef(); var the_joint:b2DistanceJointDef = new b2DistanceJointDef(); var joint:b2DistanceJoint; // public var m_world:b2World; public var m_iterations:int=10; public var m_timeStep:Number=1.0/30.0; public function HelloWorld() { // world setup 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 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; m_world.SetDebugDraw(dbgDraw); // ground the_box.SetAsBox(9,0.5); the_box.density=0; the_box.friction=0.4; the_box.restitution=0.1; bd = new b2BodyDef(); bd.position.Set(8.5, 13); var ground:b2Body=m_world.CreateBody(bd); ground.CreateShape(the_box); ground.SetMassFromShapes(); // roof the_box.SetAsBox(9,0.5); the_box.density=0; the_box.friction=0.4; the_box.restitution=0.1; bd = new b2BodyDef(); bd.position.Set(8.5, 0); var roof:b2Body=m_world.CreateBody(bd); roof.CreateShape(the_box); roof.SetMassFromShapes(); // circle the_circle.radius=2; the_circle.density=1.0; the_circle.friction=0.4; the_circle.restitution=0.3; bd = new b2BodyDef(); bd.position.Set(6, 2); circle=m_world.CreateBody(bd); circle.CreateShape(the_circle); circle.SetMassFromShapes(); // square the_box.SetAsBox(1.5,1.5); the_box.density=1.0; the_box.friction=0.4; the_box.restitution=0.1; bd = new b2BodyDef(); bd.position.Set(2, 2); var box:b2Body=m_world.CreateBody(bd); box.CreateShape(the_box); box.SetMassFromShapes(); // listeners stage.addEventListener(MouseEvent.MOUSE_DOWN, createMouse); stage.addEventListener(MouseEvent.MOUSE_UP, destroyMouse); addEventListener(Event.ENTER_FRAME, Update, false, 0, true); } public function createMouse(evt:MouseEvent):void { var body:b2Body=GetBodyAtMouse(true); if (body) { the_joint.Initialize(circle, body, circle.GetWorldCenter(),new b2Vec2(mouseX/30,mouseY/30)); the_joint.collideConnected=true; joint=m_world.CreateJoint(the_joint) as b2DistanceJoint; } } public function destroyMouse(evt:MouseEvent):void { if (joint) { m_world.DestroyJoint(joint); joint=null; } } 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()) { 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); } } } |
Let’s see what I changed from the original script
First, I changed GetBodyAtMouse function – lines 104-126 – so it only returns static objects at line 116.
Then, I modified createMouse function – lines 90-97 – in order to create a joint between the center of the ball and the mouse position in the selected static object, and obviously the destroyMouse one to remove the joint when I release the mouse.
There isn’t much more to see that you can’t see in the posts I mentioned before.
Here it is the result:
Click on a static object (green) to create a joint on the fly
No need to include the source code, just replace the script at Box2D joints: Distance Joint with this one.
Next time, we’ll see how to shoot the hook.
They can be easily customized to meet the unique requirements of your project.















(16 votes, average: 4.06 out of 5)









This post has 4 comments
Guest
Thanks, you’re the best!!!
Rendering joints with Box2D : Emanuele Feronato
[...] following script is the same you can find at Simulating a hook with Box2D but I will render the joints with lines. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [...]
James
Where is the other half of this tutorial?
New
We already got drawing boxes on the fly, drawing circles on the fly, how about joints? This is kind of that, but only on mousejoint, and thus only pinning on the background, how about joints between bodies, would love that.