Creation of a Box2D hook like the one seen on iOS Mikey Hooks game

Read all posts about "" game

Did you play Mikey Hooks? It’s an excellent platform where the hero can fire hooks and jump over spikes, holes and monster… and obviously the game is much more than this but I wanted to create some kind of hook with Box2D.

I made a very basic hook some time ago in the post Simulating a hook with Box2D but this is way better, here is how it works:

Each time you click on a static body (let’s say a rock), you create a distance joint between a dynamic body (let’s say the hero) and the static body.

Keeping the mouse down will rewind the hook, that is the distance joint is shortened, giving you a “Bionic Commando” effect.

Releasing mouse button will destroy the joint and you will be able to fire another hook.

This way you can swing around the stage.

Here is the code:

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;
		public function Main() {
			// this is the ground
			addBox(320,480,640,20,b2Body.b2_staticBody);
			// let's add some random stuff
			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);
			}
			// and finally the hero
			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 {
			// when firing the hook, let's remove old joints, if any
			if (distanceJoint) {
				world.DestroyJoint(distanceJoint);
			}
			// checking the body under the mouse
			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) {
				// if I have a body under the mouse, I create a distance joint between the hero and mouse position
				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 I release the mouse, I destroy the distance joint
			if (distanceJoint) {
				world.DestroyJoint(distanceJoint);
			}
		}
		private function manageHook():void{
			// as long as the hook is active, I shorten a bit joint distance
			if (isHooked) {
				// BODY MUST BE AWAKE!!!!!!
				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 debugDraw:b2DebugDraw=new b2DebugDraw();
			var debugSprite:Sprite=new Sprite();
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(worldScale);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
			debugDraw.SetFillAlpha(0.5);
			world.SetDebugDraw(debugDraw);
		}
		private function update(e:Event):void {
			world.Step(1/30, 10, 10);
			manageHook();
			world.ClearForces();
			world.DrawDebugData();
		}

	}

}

And this is the result:

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.

Download the source code.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers