Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Don't touch the spikes game, Game development, HTML5, Javascript and Phaser.

Last week I showed you a first take in building a “Don’t Touch the Spikes” prototype using Phaser and Matter physics, and had some problems in the creation of a body starting from a path defining a triangle – the spike. Looking at the original game, I realized the spikes can be rendered using squares rotated by 45 degrees. This allowed me to bypass the triangle path glitch and develop the full prototype in a matter of minutes. You are about to see the full game rendered in debug draw, ready for your reskin. This reminded me the good old AS3 + Box2D prototype, when most prototypes were build just using the debug draw. Look at the game:
Tap or click to jump, touch a spike and it’s game over. As you can see, spikes are actually squares rotated by 45 degrees, and we play with their horizontal position to make them appear or disappear. No new bodies are created during the game, they are all created at the beginning of the game and reused. The source code still has a lot of hardcoded values which will be optimized next time, giving you room for customization, but it’s fairly easy to understand how I created the prototype using only Matter physics native methods. Commented code will be released with next update, if I manage to improve the code a bit.
var game;
var gameOptions = {
    triangleBase: 60
}
window.onload = function() {
    var gameConfig = {
       type: Phaser.AUTO,
       width: gameOptions.triangleBase * 9.5,
       height: gameOptions.triangleBase * 15.5,
       backgroundColor: 0x000000,
       scene: playGame,
       physics: {
           default: "matter",
           matter: {
               debug: true
           }
        }
    }
    game = new Phaser.Game(gameConfig);
    window.focus();
    resize();
    window.addEventListener("resize", resize, false);
}
class playGame extends Phaser.Scene{
    constructor(){
        super("PlayGame");
    }
    create(){
        var squareSize = gameOptions.triangleBase / Math.sqrt(2);
        var spikeDistance = gameOptions.triangleBase * 1.25;
        this.leftSpikes = [];
        this.rightSpikes = [];
        for(var i = 0; i < 11; i++){
            if(i < 7){
                this.matter.add.rectangle(gameOptions.triangleBase + i * spikeDistance, game.config.height - gameOptions.triangleBase / 2, squareSize, squareSize, {
                    isStatic: true,
                    angle: Math.PI / 4,
                    label: "spike"
                });
                this.matter.add.rectangle(gameOptions.triangleBase + i * spikeDistance, gameOptions.triangleBase / 2, squareSize, squareSize, {
                    isStatic: true,
                    angle: Math.PI / 4,
                    label: "spike"
                });
            }
            var spike = this.matter.add.rectangle(- gameOptions.triangleBase / 4, gameOptions.triangleBase * 1.5 + i * spikeDistance, squareSize, squareSize, {
                isStatic: true,
                angle: Math.PI / 4,
                label: "spike"
            });
            this.leftSpikes.push(spike);
            spike = this.matter.add.rectangle(game.config.width + gameOptions.triangleBase / 4, gameOptions.triangleBase * 1.5 + i * spikeDistance, squareSize, squareSize, {
                isStatic: true,
                angle: Math.PI / 4,
                label: "spike"
            });
            this.rightSpikes.push(spike);
        }
        this.matter.add.rectangle(gameOptions.triangleBase / 4, game.config.height / 2, gameOptions.triangleBase / 2, game.config.height, {
            isStatic: true,
            label: "leftwall"
        });
        this.matter.add.rectangle(game.config.width - gameOptions.triangleBase / 4, game.config.height / 2, gameOptions.triangleBase / 2, game.config.height, {
            isStatic: true,
            label: "rightwall"
        });
        this.matter.add.rectangle(game.config.width / 2, gameOptions.triangleBase / 4, game.config.width - gameOptions.triangleBase, gameOptions.triangleBase / 2, {
            isStatic: true
        });
        this.matter.add.rectangle(game.config.width / 2, game.config.height - gameOptions.triangleBase / 4, game.config.width - gameOptions.triangleBase, gameOptions.triangleBase / 2, {
            isStatic: true
        });
        this.bird = this.matter.add.circle(game.config.width / 2, game.config.height / 2, gameOptions.triangleBase / 2);
        Phaser.Physics.Matter.Matter.Body.setVelocity(this.bird, {
            x: 7,
            y: 0
        });
        this.input.on("pointerdown", this.jump, this);
        this.matter.world.on("collisionstart", function (e, b1, b2) {
            if(b1.label == "spike" || b2.label == "spike"){
                this.scene.start("PlayGame");
            }
            if(b1.label == "leftwall" || b2.label == "leftwall"){
                this.setSpikes(true);
                Phaser.Physics.Matter.Matter.Body.setVelocity(this.bird, {
                    x: 7,
                    y: 0
                });
            }
            if(b1.label == "rightwall" || b2.label == "rightwall"){
                this.setSpikes(false);
                Phaser.Physics.Matter.Matter.Body.setVelocity(this.bird, {
                    x: -7,
                    y: 0
                });
            }
        }, this);
    }
    setSpikes(isRight){
        for(var i = 0; i < 11; i++){
            if(isRight){
                Phaser.Physics.Matter.Matter.Body.setPosition(this.rightSpikes[i], {
                    x: game.config.width + gameOptions.triangleBase / 4,
                    y: this.rightSpikes[i].position.y
                });
            }
            else{
                Phaser.Physics.Matter.Matter.Body.setPosition(this.leftSpikes[i], {
                    x: - gameOptions.triangleBase / 4,
                    y: this.leftSpikes[i].position.y
                });
            }
        }
        var randomPositions = Phaser.Utils.Array.NumberArray(0, 10);
        var numberOfSpikes = Phaser.Math.Between(3, 6);
        for(i = 0; i < numberOfSpikes; i++){
            var randomSpike = Phaser.Utils.Array.RemoveRandomElement(randomPositions);
            if(isRight){
                Phaser.Physics.Matter.Matter.Body.setPosition(this.rightSpikes[randomSpike], {
                    x: game.config.width - gameOptions.triangleBase / 2,
                    y: this.rightSpikes[randomSpike].position.y
                });
            }
            else{
                Phaser.Physics.Matter.Matter.Body.setPosition(this.leftSpikes[randomSpike], {
                    x: gameOptions.triangleBase / 2,
                    y: this.leftSpikes[randomSpike].position.y
                });
            }

        }
    }
    jump(){
        Phaser.Physics.Matter.Matter.Body.setVelocity(this.bird, {
            x: this.bird.velocity.x,
            y: -10
        })
    }
    update(){
        Phaser.Physics.Matter.Matter.Body.setVelocity(this.bird, {
            x: (this.bird.velocity.x > 0) ? 7 : -7,
            y: this.bird.velocity.y
        })
    }
};
function resize(){
    var canvas = document.querySelector("canvas");
    var windowWidth = window.innerWidth;
    var windowHeight = window.innerHeight;
    var windowRatio = windowWidth / windowHeight;
    var 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";
    }
}
Next time I will show you how to use your own graphics assets and how to add a coin to be collected, at the moment download the source code and play with it.

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