Talking about Actionscript 3, Box2D, Flash and Game development.
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:
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.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.