Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Color Jump game, Game development, HTML5, Javascript and Phaser.

As promised, here we go with the second step of Color Jump prototype.

In the first step we saw the basic prototype of the game, and now it’s time to add collectible coins, just like we did in the fourth part of “Don’t Touch the Spikes” prototype.

Look at the game:

Tap to jump. Hit the walls matching the color of the ball, or it’s game over. If you fall down, it’s game over. If you fly off the top, it’s game over. Try to collect the coins.

Exactly like in Don’t Touch the Spikes, coins introduce a new kind of Matter body called sensor. Sensors trigger collision events, but do not react with colliding body physically, so the player won’t bounce on the coin, and it’s exactly what we need.

And now you have the full commented source code, line by line:

// the game itself
let game;

// global game options
let gameOptions = {

    // world gravity
    gravity: 4,

    // ball horizontal speed
    ballSpeed: 4,

    // jump force
    jumpForce: 30,

    // amount of bars each wall is divided in
    bars: 4,

    // array with the colors to pick from
    barColors: [0x1abc9c, 0x2980b9, 0x9b59b6, 0xf1c40f, 0xc0392b, 0xecf0f1]
}

// constants used to pass "LEFT" and "RIGHT" as arguments rather than "0" and "1"
const LEFT = 0;
const RIGHT = 1;

// function to be executed when the windows has loaded
window.onload = function() {

    // object containing configuration options
    let gameConfig = {

        // render type: let the game decide if CANVAS of WEBGL
        type: Phaser.AUTO,

        // width of the game, in pixels
        width: 750,

        // height of the game, in pixels
        height: 1334,

        // background color (black)
        backgroundColor: 0x000000,

        // scene to play
        scene: playGame,

        // physics settings
        physics: {

            // we are using Matter JS
            default: "matter",
            matter: {

                // gravity settings
                gravity: {
                    x: 0,
                    y: gameOptions.gravity
                }
            }
        }
    }

    // game creation
    game = new Phaser.Game(gameConfig);

    // giving focus to the frame (if any) where the game is running in
    window.focus();

    // pure javascript to scale the canvas
    resize();
    window.addEventListener("resize", resize, false);
}

// playGame scene
class playGame extends Phaser.Scene{
    constructor(){
        super("PlayGame");
    }

    // preloading assets
    preload(){
        this.load.image("wall", "wall.png");
        this.load.image("ball", "ball.png");
        this.load.image("coin", "coin.png");
    }

    // method to be executed once, when the scene has been created
    create(){

        // arrays where to store left and right walls
        this.leftWalls = [];
        this.rightWalls = [];

        // each wall is made by "gameOptions.bars" pieces, so we actually have "gameOptions.bars" walls each side
        for(let i = 0; i < gameOptions.bars; i++){

            // adding left and right walls
            this.leftWalls[i] = this.addWall(i, LEFT);
            this.rightWalls[i] = this.addWall(i, RIGHT);
        }

        // adding the ball
        this.ball = this.matter.add.image(game.config.width / 4, game.config.height / 2, "ball");

        // setting ball body as circular
        this.ball.setCircle()

        // adding the coin, no matter where, we'll set its position later
        this.coin = this.matter.add.image(0, 0, "coin");

        // setting coin body as circular
        this.coin.setCircle();

        // setting coin body as static (not affected by gravity or collisions)
        this.coin.setStatic(true);

        // setting coin body as sensor. Will fire collision events without actually collide
        this.coin.body.isSensor = true;

        // giving the coin a label called "coin"
        this.coin.body.label = "coin"

        // this method will randomly place the coin
        this.placeCoin();

        // setting ball velocity (horizontal, vertical)
        this.ball.setVelocity(gameOptions.ballSpeed, 0);

        // waiting for pointer down input to call "jump" method
        this.input.on("pointerdown", this.jump, this);

        // waiting for a "collisionstart" event. "e" is the event, "b1" and "b2" the bodies
        this.matter.world.on("collisionstart", function (e, b1, b2) {

            // checking b1 and b2 labels to be "leftwall"
            if(b1.label == "leftwall" || b2.label == "leftwall"){

                // handling collisions on the LEFT side
                this.handleWallCollision(LEFT, b1, b2);
            }

            // checking b1 and b2 labels to be "rightwall"
            if(b1.label == "rightwall" || b2.label == "rightwall"){

                // handling collisions on the RIGHT side
                this.handleWallCollision(RIGHT, b1, b2);
            }

            // checking b1 and b2 labels to be "coin"
            if(b1.label == "coin" || b2.label == "coin"){

                // calling the method to move the coin elsewhere
                this.placeCoin();
            }
        }, this);
    }

    // method to add a wall, given its number (0 = top) and it side
    addWall(wallNumber, side){

        // getting "wall" preloaded image
        let wallTexture = this.textures.get("wall");

        // determining wall height according to game height and the number of bars
        let wallHeight = game.config.height / gameOptions.bars;

        // determining wall x position
        let wallX = side * game.config.width + wallTexture.source[0].width / 2 - wallTexture.source[0].width * side;

        // determining wall y position
        let wallY = wallHeight * wallNumber + wallHeight / 2;

        // adding the wall
        let wall = this.matter.add.image(wallX, wallY, "wall");

        // the wall is static
        wall.setStatic(true);

        // giving the wall the proper label
        wall.body.label = (side == RIGHT) ? "rightwall" : "leftwall"

        // setting wall height
        wall.displayHeight = wallHeight;

        // returning the wall object
        return wall
    }

    // method to place the coin
    placeCoin(){

        // just placing the coin in a random position between 20% and 80% of the game size
        this.coin.x = Phaser.Math.Between(game.config.width * 0.2, game.config.width * 0.8);
        this.coin.y = Phaser.Math.Between(game.config.height * 0.2, game.config.height * 0.8);
    }

    // method to handle ball Vs wall collision
    handleWallCollision(side, bodyA, bodyB){

        // if the ball and the wall have different colors...
        if(bodyA.color != bodyB.color){

            // restart the game
            this.scene.start("PlayGame");
        }

        // calling a method to paint the walls
        this.paintWalls((side == LEFT) ? this.rightWalls : this.leftWalls);

        // updating ball velocity
        this.ball.setVelocity(gameOptions.ballSpeed, this.ball.body.velocity.y);
    }

    // method to paint the walls, in the argument the array of walls
    paintWalls(walls){

        // looping through all walls
        walls.forEach(function(wall){

            // picking a random color
            let color = Phaser.Math.RND.pick(gameOptions.barColors);

            // tinting the wall
            wall.setTint(color);

            // also assigning the wall body a custom "color" property
            wall.body.color = color;
        });

        // picking a random wall
        let randomWall = Phaser.Math.RND.pick(walls);

        // painting the ball with the same color used by the random wall
        this.ball.setTint(randomWall.body.color);

        // also assigning the ball body a custom "color" property
        this.ball.body.color = randomWall.body.color;
    }

    // method to jump
    jump(){

        // setting new ball velocity
        this.ball.setVelocity((this.ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, -gameOptions.jumpForce);
    }

    // method to be called at each frame
    update(){

        // updating ball velocity
        this.ball.setVelocity((this.ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, this.ball.body.velocity.y);

        // if the ball flies off the screen...
        if(this.ball.y < 0 || this.ball.y > game.config.height){

            // restart the game
            this.scene.start("PlayGame");
        }
    }
};

// pure javascript to resize the canvas and scale the game
function resize(){
    let canvas = document.querySelector("canvas");
    let windowWidth = window.innerWidth;
    let windowHeight = window.innerHeight;
    let windowRatio = windowWidth / windowHeight;
    let gameRatio = game.config.width / game.config.height;
    if(windowRatio < gameRatio){
        canvas.style.width = windowWidth + "px";
        canvas.style.height = (windowWidth / gameRatio) + "px";
    }
    else{
        canvas.style.width = (windowHeight * gameRatio) + "px";
        canvas.style.height = windowHeight + "px";
    }
}

What about some particle effects next time? I will show you how to add eye-candy effects. Download the source code.

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