Wednesday, March 2, 2016

Using "shutdown" to Save State in Phaser

Today is the comic that I've been working on in all my spare time for the past week, but have been thinking about for about a year. For such a long time, I've wanted to work a Dragon Warrior parody into a comic. That game was such a major part of my childhood. I played it for countless hours on my NES, along with its sequels.

If you're not as familiar with it as I am (my wife had never heard of it), it was the game that introduced console turn-based RPGs to the American market. You play a warrior trying to save a princess and slay a dragon by defeating various monsters to gain gold and experience. The gold gets you better armor and weapons, while the experience ups your level for more strength, magic, etc. As you walk around the world, a battle starts randomly. You and the monster take turns hitting each other until one of you dies. Assuming you win, the game returns to the map screen and you walk around some more.

If you haven't seen the comic yet, take a look at it. My parody of the game is embedded in the 3rd frame, and is completely playable.

The walking-around game state.

When I implemented this in Phaser, I made the walking-around-on-the-map one game state and the fighting-a-monster (or a printer in my case) another game state. After the fight ends, I wanted to go back to the walking-around state but put the frog at the same map position he was before the fight started - not reset everything in the state back to the default. But the way Phaser works is that when you start a game state, the create function is always called. How could I ensure that the frog ended up back where he belonged each time that happened?

The fighting state. Kick that printer!

The answer is to make use of the shutdown function on the state. I hadn't used this one before; my game state objects never defined it. But it is important if you wanted to save the current values of anything in your game before switching states, as it is called by Phaser when one state is being stopped but before another starts. I used it to save the frog's current position, which I then used the next time create was called.

Here is a sample of the code, to help in the explanation.

function walkAround() {

    // default frog's position
    var fPos = { x: 200, y: 500 };

    function create() {

        // create the frog wherever fPos says to put him
        frog = this.add.sprite(fPos.x, fPos.y, "frog", 0);

        // ... other stuff ...

    }
    
    function shutdown() {
        
        // save the frog's current position to use
        // next time create is called.
        fPos.x = frog.position.x;
        fPos.y = frog.position.y;
        
    }

    return {
        create: create,
        shutdown: shutdown
    };

}

function fight() {

    // ... all the stuff for the fighting state ...

    return {
        // an actual state object
    };

}

var s1 = walkAround();
var s2 = fight();
 
var game = new Phaser.Game(width, height, Phaser.CANVAS, "cell-2");
 
game.state.add("walking",  s1);
game.state.add("fighting", s2);

game.state.start("walking");

The fPos variable gets a default value when it is initialized. This is the value used the very first time create is called. But after shutdown is called, fPos changes. Since the state object isn't ever destroyed, fPos retains its value and the next time create is called, the frog is put in his last known location.

This technique will work for anything in your game state that you'd like to save and restore, such as when your player switches to a menu state and then returns to play.

Make sure you check out the comic and play the game! If you'd like to see the complete source code for the game (or anything else on the comic) you can find the repo on GitHub.

Amphibian.com comic for 2 March 2016