Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Mikey Hooks game, Game development, HTML5, Javascript and Phaser.

Mikey Hooks is a great game. Fullstop.

I liked so much the way the player used the hook, and I built prototypes using Flash + Box2D, Flash + Nape (Nape seems to be discontinued), Phaser + Box2D and Unity.

No matter the language, engine or framework you are using to build your hooks, they will all rely on a constraint called distance joint.

A constraint on a system is a parameter that the system must obey. In this case, the constraint is a distance joint which says “no matter what happens, there must be a given distance between two bodies”.

And that’s all:

Click on a box and hold to create a distance joint from the ball to the box working like a hook and start swinging by clicking and holding on different boxes.

The code is just a matter of checking if we clicked on a box, then create the joint until the mouse is released or a collision occurred.

Here it is, fully commented:

let game;
let gameOptions = {
    gravity: 1,             // game gravity
    terrainObjects: 20,     // amount of terrain objects
    ballRadius: 20,         // radius of the ball
    constraintSpeed: 4,     // constraint shrinkage speed
    minBoxSize: 50,        // minimum box size
    maxBoxSize: 200         // maximum box size
}
const WALL = 0;
const BALL = 1;
window.onload = function() {

    // game configuration
    let gameConfig = {
        type: Phaser.AUTO,
        scale: {
            mode: Phaser.Scale.FIT,
            autoCenter: Phaser.Scale.CENTER_BOTH,
            parent: "thegame",
            width: 1334,
            height: 750
        },
        scene: playGame,
        physics: {
            default: "matter",
            matter: {
                gravity: {
                    y: gameOptions.gravity
                },
                debug: true
            }
        }
    }
    game = new Phaser.Game(gameConfig);
    window.focus();
}
class playGame extends Phaser.Scene{
    constructor(){
        super("PlayGame");
    }
    create(){

        // I want physics world to be updated 30 times per second
        this.matter.world.update30Hz();

        // adding world bounds. Basically four walls
        this.matter.world.setBounds(10, 10, game.config.width - 20, game.config.height - 20);

        // placing some random static boxes labeled as WALL
        for (let i = 0; i < gameOptions.terrainObjects; i++){
            let posX = Phaser.Math.Between(0, game.config.width);
            let posY = Phaser.Math.Between(0, game.config.height);
            let width = Phaser.Math.Between(gameOptions.minBoxSize, gameOptions.maxBoxSize);
            let height = Phaser.Math.Between(gameOptions.minBoxSize, gameOptions.maxBoxSize);
            let poly = this.matter.add.rectangle(posX, posY, width, height, {
                isStatic: true
            });
            poly.label = WALL;
        }

        // adding a bouncing ball labeled as BALL
        this.ball = this.matter.add.circle(game.config.width / 2, game.config.height / 2, gameOptions.ballRadius, {
            restitution: 0.5
        });
        this.ball.label = BALL;

        // event listeners
        this.input.on("pointerdown", this.fireHook, this);
        this.input.on("pointerup", this.releaseHook, this);

        // no ropes at the beginning
        this.rope = null;

        // when the ball collides on something, we'll remove the hook
        this.matter.world.on("collisionstart", function(e, b1, b2){
            if(b2.label == BALL){
                this.releaseHook();
            }
        }, this)
    }

    // method to fire the hook
    fireHook(e){

        // getting all bodies
        let bodies = this.matter.world.localWorld.bodies;

        // looping through bodies
        for(let i = 0; i < bodies.length; i++){

            // getting body vertices
            let vertices = bodies[i].parts[0].vertices;

            // do the vertices contain the pointer AND the body is labeled as WALL?
            if(Phaser.Physics.Matter.Matter.Vertices.contains(vertices, e.position) && bodies[i].label == WALL){

                // calculate the distance between the ball and the body
                let distance = Phaser.Math.Distance.Between(this.ball.position.x, this.ball.position.y, bodies[i].position.x, bodies[i].position.y)

                // is the distance greater than ball radius?
                if(distance > gameOptions.ballRadius){

                    // add the constraint
                    this.rope = this.matter.add.constraint(this.ball, bodies[i], distance, 0);
                }
                break;
            }
        }
    }

    // method to remove the hook
    releaseHook(){

        // is there a constraint? Remove it
        if(this.rope){
            this.matter.world.removeConstraint(this.rope);
            this.rope = null;
        }
    }

    // method to be executed at every frame
    update(){

        // is there a constraint? Shrink it
        if(this.rope){
            this.rope.length -= gameOptions.constraintSpeed;
        }
    }
};

At the moment the hook always starts from the center of the box, but I am working on a more interesting way using raycasting… stay tuned and meanwhile download the source code of this example.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.