Monday, February 22, 2016

Setting Up Level Bosses with Phaser

I've reached the phase of my development on my Phaser platformer where I refactor everything. This weekend, it was the level bosses. If you looked at much earlier versions of the game or read my blog posts from a couple months ago, you might remember that I had one sandbox level with a dinosaur as the boss at the end. He was pretty much hard-coded in there, so adding different bosses for each level was difficult.

To make it better, I added a field to my level objects called boss. I assign a function to that field, which creates the boss Sprite. I can assign different "boss" functions to each level.

function beaver(game, group, frog) {
    // ... set up the boss beaver
}

function dinosaur(game, group, frog) {
    // ... set up the boss dinosaur
}

var levelOne = { // Vector Factory
        map: "Level1",
        music: "assets/audio/Ouroboros.mp3",
        background: "#141414",
        boss: beaver
};

var levelTwo = { // Binary Trees
        map: "Level2",
        music: "assets/audio/Club_Diver.mp3",
        background: "#000066",
        boss: dinosaur
};

// ... define other levels here ...

var gameState = {
        levels: [],
        currentLevel: -1,
        lives: 3
};

// populate the levels array (add more the same way)    
gameState.levels[0] = levelOne;
gameState.levels[1] = levelTwo;

In my game's create function, I call the boss function of whatever level is currently being played. I then add the kill behavior to the boss Sprite, which is to end the level and return to the stage select screen.

function create() {

    // ... other stuff ...

    // create a group for all the enemies
    enemies = this.add.group();

    // create our hero sprite
    frog = createFrog();

    // --------------- set up the boss for this level
        
    var theBoss = gameState.levels[gameState.currentLevel].boss(this, enemies, frog);
    theBoss.events.onKilled.add(function() {
        // this level is complete! change state!
        this.state.start("stageSelect");
    }, this);

    // ... other stuff ...

}

Now it's fairly easy to add new bosses and even switch them around from one level to another. But you may wonder why I chose to always pass in those three parameters to the boss functions - game, group, and frog.

The first thing that the boss setup function must do is to create the boss Sprite, and to accomplish that I need the game object, the group in which to place this boss, and a reference to the frog object so the boss's behavior can change based on attributes such as the frog's proximity or other such things.

// function create the boss beaver
function beaver(game, group, frog) {

    // create this boss:
    //     150 pixels from the far right edge of the level,
    //     100 pixels from the top of the level,
    //     using the spritesheet with the key of "beaver"
    var obj = game.add.sprite(game.world.width - 150, 100, "beaver", 0, group);

    // ... other stuff ...

    return obj;

}

If these little snippets of code aren't enough, you can see the game's complete source code on GitHub.

Try the game out for yourself at Amphibian.com, and also be sure to read today's comic while you're there (or go right to the comic with the link below!).

Amphibian.com comic for 22 February 2016