A Finite State Machine implementation for use with Javascript games

A Finite State Machine implementation for use with Javascript games

onedayitwillmake 2 comments
gamedev javascript

Currently I’m working on a new Javascript/WebGL game called ChuClone. It’s been a lot of fun to work on so far. Having a good editor has been a key in that, as it allows you to write javascript in a more application like style, than strictly a series of DOM manipulation functions.

For this game I wanted to use a Finite State Machine to handle my gameplay states.

An example of such a system is if you think of your game as a connection of screens, for example:
StartScreen
GamePlayScreen
EndScreen

It’s likely that each one of those will have to do some initialization upon entering, update things while running, and finally do some cleaning up when exiting.

An initial approach is to track the current state with a bunch of Boolean values, such as:
_isPlaying;
_isSelectingCharacter;

This system is very useful during the early part of coding since you’re simply trying to test out a concept as quickly as possible without too much fuss. It starts to get out of hand once the game starts doing more interesting things, many states must be tracked – but the real problem is the nested nature of such a system.

Once you have many nested checks involved, bugs start to pop up because you did this, while thatFlag was on, before thatOther flag was turned off.

This is where a Finite State Machine for your game can come to the rescue, allow each GameState to track it’s own variables for it’s system and generally not communicate with one another. This helps you architecture your system in such a way that you don’t end up taking TOO much advantage of javascripts loose nature, which is sometimes just enough rope to get yourself into trouble.

With an FSM should something trigger it, you can push a new GameState onto the stack and and pop back to the previous one once complete, or push to a whole other GameState. A good example of this is the scenario:

PlayingGame -> PauseScreen -> PlayingGame

Here we would tell the FSM to push a new state, and when the user selects PauseScreen simply pop the state out of the FSM and it’s like it was never there. Since only the currentstate has the ‘update‘ called on it the PlayGame state is now paused without adverse side effects.

So this is the FSM implementation I decided on for my game ChuClone, so far it’s working quite well.

StateMachine.js

(function(){
   ChuClone.namespace("ChuClone.model.FSM");
 
    var instance = null;
    ChuClone.model.FSM.StateMachine = function() {
        if(instance == null) instance = this;
        else console.error("ChuClone.model.FSM.StateMachine - Instance already exist!");
    };
 
    ChuClone.model.FSM.StateMachine.prototype = {
 
        /**
         * @type {ChuClone.model.FSM.State}
         */
        _currentState: null,
        /**
         * @type {ChuClone.model.FSM.State}
         */
        _previousState: null,
        /**
         * @type {ChuClone.model.FSM.State}
         */
        _nextState: null,
 
        /**
         * Set the first state (without making call to previous state)
         * @param {ChuClone.model.FSM.State}
         */
        setInitialState: function( aState ) {
            this._currentState = aState;
            this._currentState.enter();
        },
 
        /**
         * Switch to another state
         * @param {ChuClone.model.FSM.State} aState
         */
        changeState: function( aState ) {
            this._currentState.exit();
            this._previousState = this._currentState;
 
            this._currentState = aState;
            this._currentState.enter();
        },
 
        /**
         * Switch to previous state
         */
        gotoPreviousState: function() {
            this.changeState( this._previousState );
        },
 
        /**
         * Switches to the next state
         */
        gotoNextState: function() {
            this.changeState( this._nextState );
        },
 
        /**
         * Update the current state
         */
        update: function() {
            if( this._currentState ) {
                this._currentState.update();
            }
        }
    };
 
    /**
	 * @return {ChuClone.editor.WorldEditor}
	 */
	ChuClone.model.FSM.StateMachine.getInstance = function() {
 
		if( instance == null ) {
			debugger;
			throw new Error("ChuClone.model.FSM.StateMachine - No instance!");
		}
 
		return instance;
	}
})();

State.js

(function(){
    ChuClone.namespace("ChuClone.model.FSM");
    ChuClone.model.FSM.State = function() {
 
    };
 
    ChuClone.model.FSM.State.prototype = {
 
        /**
         * Container of closures used in event callbacks
         * @type {Object}
         */
        _closures   : {},
 
        enter: function() {
 
        },
 
        update: function() {
 
        },
 
        exit: function() {
 
        },
    }
})();

Usage

// Initialize the state machine
this._stateMachine = new ChuClone.model.FSM.StateMachine();
 
// Set the initial state - this just means we don't call exit on the 'previousState'
this._stateMachine.setInitialState( new ChuClone.states.EditState() );
 
var that = this;
(function loop() {
this._stateMachine.update();
window.requestAnimationFrame(loop, null);
})();
// Later on... Change the state to PlayLevelState
this._stateMachine.changeState( new ChuClone.states.PlayLevelState() );
 
// Even More Later on... User is done play testing, return to edit state
this._stateMachine.gotoPreviousState();

And there you have it – a simple FSM for javascript games.

2 Comments

Jonathan Wright

November 29, 2012 at 10:40 pm

Nice.

I come from a background in HTML graphics and page layout. While programming is not foreign to me, it has taken several years to learn the ropes.

I recently read through a book on Actionscript that told me how to make a FSM, although slightly different. In my case, it seems that each state function determines what logically comes next, where as yours allows a little more user control.

For instance, the following function calls a “new game”, and at the end of the function it switches to a “new level” function.

And mine has no initial state, since my AS3 state machine is called initially from the Flash IDE stage.

public function systemNewGame():void {
//trace(“System: New Game Screen”);
addChild(game);
game.addEventListener(CustomEventScoreBoardUpdate.UPDATE_TEXT, scoreBoardUpdateListener, false, 0, true);
game.addEventListener(CustomEventLevelScreenUpdate.UPDATE_TEXT, levelScreenUpdateListener, false, 0, true);
game.addEventListener(CustomEventSound.PLAY_SOUND, soundEventListener, false, 0, true);

game.addEventListener(Game.GAME_OVER, gameOverListener, false, 0, true);

game.addEventListener(Game.NEW_LEVEL, newLevelListener, false, 0, true);

game.newGame();
switchSystemState(FrameWorkStates.STATE_SYSTEM_NEW_LEVEL);
}

 Reply

onedayitwillmake

December 8, 2012 at 6:49 am

Hi Jonathan,

Interesting, I am familiar with AS3 it’s a great language although I dislike the flash player’s quirks (there are many, why is this doing X!).

It seems that your implementation is actually a game controller, and FSM wrapped into one.
In my implementation I usually create a gamecontroller, which contains an FSM instance.

You can see it in action in http://chuclone.com, which is open sourced.
It basically goes like this:

IntroState
-> GameState
-> PauseState
-> GameState
-> InstructionsState
->GameState
->EndScreenState
->GameState

I find it more flexible as sometimes only a state is aware of which state should be created next.

 Reply

Leave a Reply


*