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.

When I showed you the “Don’t Touch the Spikes” rendered with debug draw in this post, I told you I would have added graphic assets in next update, and here we go.

This update basically merges the features of the first step when we saw how to bind Matter physics to Phaser images with the complete game engine introduced in step 2 when you had a completely playable game just rendered in debug draw.

Ball movement has also been improved, have a look at the game:

Both graphic assets and the debug draw are visible, to let you see how this stuff works.

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.

I also added some more values in gameOptions global object to easily customize ball movement.

The source code is still uncommented, but I am adding comments with next update

var game;
var gameOptions = {
    triangleBase: 60,
    ballSpeed: 7,
    jumpForce: 10
}
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");
    }
    preload(){
        this.load.image("spike", "spike.png");
        this.load.image("wall", "wall.png");
        this.load.image("ball", "ball.png");
    }
    create(){
        var spikeDistance = gameOptions.triangleBase * 1.25;
        this.leftSpikes = [];
        this.rightSpikes = [];
        for(var i = 0; i < 11; i++){
            if(i < 7){
                this.addSpike(gameOptions.triangleBase + i * spikeDistance, game.config.height - gameOptions.triangleBase / 2);
                this.addSpike(gameOptions.triangleBase + i * spikeDistance, gameOptions.triangleBase / 2);
            }
            this.leftSpikes.push(this.addSpike(- gameOptions.triangleBase / 4, gameOptions.triangleBase * 1.5 + i * spikeDistance));
            this.rightSpikes.push(this.addSpike(game.config.width + gameOptions.triangleBase / 4, gameOptions.triangleBase * 1.5 + i * spikeDistance));
        }
        this.addWall(gameOptions.triangleBase / 4, game.config.height / 2, gameOptions.triangleBase / 2, game.config.height, "leftwall");
        this.addWall(game.config.width - gameOptions.triangleBase / 4, game.config.height / 2, gameOptions.triangleBase / 2, game.config.height, "rightwall");
        this.addWall(game.config.width / 2, gameOptions.triangleBase / 4, game.config.width - gameOptions.triangleBase, gameOptions.triangleBase / 2, "");
        this.addWall(game.config.width / 2, game.config.height - gameOptions.triangleBase / 4, game.config.width - gameOptions.triangleBase, gameOptions.triangleBase / 2, "");
        var ballTexture = this.textures.get("ball");
        this.ball = this.matter.add.image(game.config.width / 4, game.config.height / 2, "ball");
        this.ball.setScale(gameOptions.triangleBase / ballTexture.source[0].width);
        this.ball.setBody({
            type: "circle",
            radius: gameOptions.triangleBase / 2
        });
        this.ball.setScale(gameOptions.triangleBase / ballTexture.source[0].width);
        this.ball.setVelocity(gameOptions.ballSpeed, 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);
                this.ball.setVelocity(gameOptions.ballSpeed, this.ball.body.velocity.y);
            }
            if(b1.label == "rightwall" || b2.label == "rightwall"){
                this.setSpikes(false);
                this.ball.setVelocity(-gameOptions.ballSpeed, this.ball.body.velocity.y);
            }
        }, this);
    }
    addWall(x, y, w, h, label){
        var wallTexture = this.textures.get("wall");
        var wall = this.matter.add.image(x, y, "wall", null, {
            isStatic: true,
            label: label
        });
        wall.setScale(w / wallTexture.source[0].width, h / wallTexture.source[0].width);
    }
    addSpike(x, y){
        var spikeTexture = this.textures.get("spike");
        var squareSize = gameOptions.triangleBase / Math.sqrt(2);
        var squareScale = squareSize / spikeTexture.source[0].width;
        var spike = this.matter.add.image(x, y, "spike", null, {
            isStatic: true,
            label: "spike"
        });
        spike.setScale(squareScale);
        spike.rotation = Math.PI / 4;
        return spike;
    }
    setSpikes(isRight){
        for(var i = 0; i < 11; i++){
            if(isRight){
                this.rightSpikes[i].x = game.config.width + gameOptions.triangleBase / 4;
            }
            else{
                this.leftSpikes[i].x = - gameOptions.triangleBase / 4;
            }
        }
        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){
                this.rightSpikes[randomSpike].x = game.config.width - gameOptions.triangleBase / 2;
            }
            else{
                this.leftSpikes[randomSpike].x = gameOptions.triangleBase / 2;
            }
        }
    }
    jump(){
        this.ball.setVelocity((this.ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, -gameOptions.jumpForce);
    }
    update(){
        this.ball.setVelocity((this.ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, this.ball.body.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";
    }
}

Which features should I add? Do you have suggestions? Some coins to collect? A physics explosion effect when the player dies? Give me feedback and 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.