Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Box2D, HTML5, Javascript and Phaser.

Now that Flash is dead, a lot of physics games powered by Box2D are
destined for oblivion.

I still consider Box2D the most powerful physics engine to build simple physics games, and I know what I am talking about since I wrote almost 200 tutorials on this blog and I published a book which has been rated with five stars on Amazon (don’t buy it, as it covers Box2D for Flash, I might consider to rewrite it to be used with Phaser).

The best Box2D JavaScript port, in my opinion, is Planck.js, which also features Space, an interactive playground to build, test and modify your projects.

I already showed you an example a long time ago, but it’s definitively time to write more tutorials about it, to bring cute physics games to a new life.

Here we go with an example using a revolute joint to simulate a bar.

A revolute joint forces two bodies to share a common anchor point, often called a hinge point. The revolute joint has a single degree of freedom: the relative rotation of the two bodies. This is called the joint angle.

Look at this example:

There is no interactivity, but random boxes are created each 1.5 seconds and fall over two bodies with a revolute joint and a motor.

The result is a moving platform like in my old Stabilize! prototype which would be interesting to build again using these modern libraries.

Have a look at the completely commented source code:

let game;
window.onload = function() {
    let gameConfig = {
        type: Phaser.AUTO,
        scale: {
            mode: Phaser.Scale.FIT,
            autoCenter: Phaser.Scale.CENTER_BOTH,
            parent: "thegame",
            width: 600,
            height: 600
        },
        scene: playGame
    }
    game = new Phaser.Game(gameConfig);
    window.focus();
}
class playGame extends Phaser.Scene {
    constructor() {
        super("PlayGame");
    }
    create() {

        // Box2D works with meters. We need to convert meters to pixels.
        // let's say 30 pixels = 1 meter.
        this.worldScale = 30;

        // world gravity, as a Vec2 object. It's just a x, y vector
        let gravity = planck.Vec2(0, 3);

        // this is how we create a Box2D world
        this.world = planck.World(gravity);

        // creation of the pivot body and the bar body with a custom method, "createBox", explained at line
        let pivot = this.createBox(game.config.width / 2, game.config.height / 5 * 4, 10, 10, false);
        let bar = this.createBox(game.config.width / 2, game.config.height / 5 * 4, game.config.width * 0.8, 20, true);

        // a revolute joint
        this.revoluteJoint = this.world.createJoint(planck.RevoluteJoint({

            // first body
            bodyA: pivot,

            // second body
            bodyB: bar,

            // bodies acnhor point
            anchorPoint: bar.getWorldCenter(),

            // max motor torque force
            maxMotorTorque: 120,

            // motor speed
            motorSpeed: 0,

            // the motor is enabled
            enableMotor: true
        }));

        // the rest of the script just creates a random box each 1500ms, then restarts after 100 iterations
        this.tick = 0;
        this.time.addEvent({
            delay: 1500,
            callbackScope: this,
            callback: function() {
                this.createBox(Phaser.Math.Between(100, game.config.width - 100), -100, Phaser.Math.Between(20, 80), Phaser.Math.Between(20, 80), true);
                this.tick ++;
                if (this.tick == 100) {
                    this.scene.start("PlayGame");
                }
            },
            loop: true
        });
    }

    // here we go with some Box2D stuff
    // arguments: x, y coordinates of the center, with and height of the box, in pixels
    // we'll conver pixels to meters inside the method
    createBox(posX, posY, width, height, isDynamic) {

        // this is how we create a generic Box2D body
        let box = this.world.createBody();
        if (isDynamic) {

            // Box2D bodies born as static bodies, but we can make them dynamic
            box.setDynamic();
        }

        // a body can have one or more fixtures. This is how we create a box fixture inside a body
        box.createFixture(planck.Box(width / 2 / this.worldScale, height / 2 / this.worldScale));

        // now we place the body in the world
        box.setPosition(planck.Vec2(posX / this.worldScale, posY / this.worldScale));

        // time to set mass information
        box.setMassData({
            mass: 1,
            center: planck.Vec2(),

            // I have to say I do not know the meaning of this "I", but if you set it to zero, bodies won't rotate
            I: 1
        });

        // now we create a graphics object representing the body
        var color = new Phaser.Display.Color();
        color.random();
        color.brighten(50).saturate(100);
        let userData = this.add.graphics();
        userData.fillStyle(color.color, 1);
        userData.fillRect(- width / 2, - height / 2, width, height);

        // a body can have anything in its user data, normally it's used to store its sprite
        box.setUserData(userData);

        return box;
    }

    update(t, dt) {

        // advance world simulation
        this.world.step(dt / 1000 * 2);

        // crearForces  method should be added at the end on each step
        this.world.clearForces();

        // adjust joint motor speed according to its angle
        this.revoluteJoint.setMotorSpeed(this.revoluteJoint.getJointAngle() * -0.1)

        // iterate through all bodies
        for (let b = this.world.getBodyList(); b; b = b.getNext()) {

            // get body position
            let bodyPosition = b.getPosition();

            // get body angle, in radians
            let bodyAngle = b.getAngle();

            // get body user data, the graphics object
            let userData = b.getUserData();

            // adjust graphic object position and rotation
            userData.x = bodyPosition.x * this.worldScale;
            userData.y = bodyPosition.y * this.worldScale;
            userData.rotation = bodyAngle;
        }
    }
};

We can create old physics games using Phaser and Planck, are you interested in more tutorials about it? Download the source code and give me feedback.

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