Monday, December 28, 2015

More Levels, Fewer States

A New Level
Last week when I added a second level to my platformer, I used multiple Phaser State objects. I had one for each level plus one for the "select a level" mode. While this worked, I wasn't particularly happy with it because every one of the level's State object was identical. It seemed to me that there should have been a better way.

As is often the case with me, I work on these games late at night and usually only for an hour or so, and I don't think of what is later the obvious solution until I've been away from it for a while. Over the weekend, I came to the conclusion that I should only be using a single State for all the different levels and merely changing which map gets loaded by other means.

Here are those other means... First, I created some simple objects which contain the map and music asset keys for each level. I put them all in a map inside an object I called gameState. This is different from a Phaser State object - I use it to keep track of my own personal state information. So far, that means which map is being played and what background music to use. I pass this gameState object to the constructors for both the stage select and the playable stage.

var sandboxLevel = {
        map: "LevelSandbox",
        music: "Ouroboros"
};

var levelOne = {
        map: "Level1",
        music: "DangerStorm"
};

var gameState = {
        levels: [],
        currentLevel: "sb"
};

gameState.levels["sb"] = sandboxLevel;
gameState.levels["one"] = levelOne;

var theStage = stage(gameState);
var stageSelectState = selectStage(gameState);

var game = new Phaser.Game(width, height, Phaser.CANVAS, "gameArea");

game.state.add("stageSelect", stageSelectState, true);
game.state.add("level", theStage);

As you can see in my code snippets above, I now only have to add two States to the Game. Inside the update function for the stage select state, I simply manipulate my gameState object before switching the Phaser State to the playable level.

function update() {

    if (keys.s.isDown) {
        // sandbox level is selected...
        gameState.currentLevel = "sb";
        this.state.start("level");
    } else if (keys.o.isDown) {
        // level one is selected...
        gameState.currentLevel = "one";
     this.state.start("level");
    }

}

Once a new State is started, the create function gets called on it. In my create function, I use the gameState object to get the current level's map and background music.

function create() {

    mapKey = gameState.levels[gameState.currentLevel].map;
    musicKey = gameState.levels[gameState.currentLevel].music;

    // ... other stuff ...

    var map = this.add.tilemap(mapKey);
    var bgmusic = this.sound.add(musicKey);

    // ... other stuff ...

}

That's it. I like this much better than that first attempt. It should be trivial now to add as many stages as I want. I really only want 8. But anyway...

You can play the game at http://amphibian.com/eight-bit and you can view the complete source code on GitHub. Take a look at today's comic before you go. I brought back Science Frog doing tech support for the other frogs, because it's funny.

Amphibian.com comic for 28 December 2015