8bitrocket.com
21May/070

Advanced Flash 8 Game Programming: A Finite State Machine Game Loop.

One of the most unorganized things in my games are the actual game loops. The game loop is the meat of the game and although it usually starts off to be a pretty simple select case statement running inside of an interval, once I get fully involved in a game, it can become a nightmare of Boolean checks and balances. Also, up until now I have relied heavily on the timeline for a lot of my game loop. The main menu, high score screen, instructions screens, etc have all been individual frames, and the game loop has been a separate class that I instantiate a single instance of. Starting with AS3 and Flash CS3, the timeline will become less and less important to Actionscript developers. To prepare, I decided to design a simple, flexible state machine game loop that will encompass all of the states I will need. There isn't enough room here to create the ultimate game loop, but we will create one with enough flexibility to be modified and extended to any game and any other state based program model.

First, what is a finite state machine? A state machine is an abstract machine that can only exist in any one of a set of predetermined states. State machines are all around us, and we use them in programming everyday. In my old Perl 5 / CGI days, I used a rudimentary one without even knowing. I would have the CGI pass a mode variable in either hidden inside a form post or on the query string. This mode var would call a function in the Perl to paint the screen with the right form or images, etc. mode=1 might be to display a form, mode=2 might be the evaluation of the form and the display of the confirmation, and mode=3 might be the error messages when a form element was not completed properly. In game design, I have modes controlled by the timeLine such as "instructionsScreen", "gameScreen" and highscoreScreen" and gameplay modes such as "startGame", "startLevel", "runLevel", etc. Controlling the change between these modes are Boolean variables such as "levelStarted", "levelPaused", "helped", etc.

In my research into creating a game loop state machine, I have come across many different implementations. Some are as simple as a select case switch statement. I have used these before and they are the root cause of the unorganized and unwieldy code mess that I want to avoid in the future. I have seen Java implementations that include event broadcasting, I have seen C++ versions with callback functions, I have even seen C versions done completely with a multidimensional array. While all of these are great, I would have nothing to write about and no challenge to undertake if I just copied one of those and went on with my work. No, I have to make things difficult, and also, I want to make them easier for myself in the future.

So, I have decided to create my own Finite State Machine Game Loop pattern. I would like to start with an abstract class called state, but Actionscript 2.0 does not have abstract classes. To make this simple, I will create a simple class called State that all of the individual states will extend from.. The use of the class will allow polymorphism of the states, and the state controller (GameEngine) will be able to loop through a set of State instances that are also instances of their own state.

What we will do next is create a very simple, but extensible model for the state machine. We only need 2 states for our simple example: StateGameSetUp and StateGameRun. These two will extend the class called State. Each state will have a Run() method that will be fired off every interval. The State parent class will have a completed() method that will callback to the GameEngine and inform it that the state has completed its work. The State class will also contain variables to hold a reference to the GameEngine and a Boolean variable called "isComplete". The GameEngine will instantiate the needed states, put them into an array of the parent class, State, and begin to fire off the run() method of the first state. This methodology will allow the GameEngine to be free of extraneous code, and keep all of the code for each state encapsulated. There certainly are other ways to accomplish this, and I am in no way an expert in OOP or design patterns. For now, this seems to be a simple, clean implementation. It can be extended through the use of multiple state machines. For instance, the StateGameRun state will have its own list of states such as "paused", "getKeys", "checkCollisions", "moveEnemy", "movePlayer", "renderObjects". Those can be handled in another state machine specific to StateGameRun. This will allow the code to be even further refined, and easier to read and update. Also, by compartmentalizing the code as such, it helps with self documentation.

First the main time line. There are two text boxes on the timeline called:setup_txt, and run_txt. These are used by our simple app to give status and to demonstrate how we will access the timeline from within our class structure. The code on the frameone of the time line looks like this:
cc lang="javascript" width="550"]
trace("game starting");
import com.game.GameEngine;
var game:GameEngine=new GameEngine(this);
[/cc]
 

That's it, nothing special here. All of the classes needed will be in a package structure like this "com.game.*". The com/ folder will need to be in the root of your app for this example. Obviously, you can set your class path to include the com.game.* classes if need be.

The next set of code of for the GameEngine class:

[cc lang="javascript" width="550"]
import com.game.StateGameSetUp;
import com.game.StateGameRun;
import com.game.State;
import mx.utils.Delegate;

class com.game.GameEngine {
var aState:Array=[];
// all of the states will implement the IState interface,
// so you can add them all to an array and enumerate through them
var GAME_RUN:StateGameRun;
var GAME_SETUP:StateGameSetUp;

var currentState:State;
var enumState:Number=0;
var mainTL:MovieClip;
var intervalVal:Number;

public function GameEngine(timeLine:MovieClip) {
mainTL = timeLine;
GAME_SETUP = new StateGameSetUp(this);
aState.push(GAME_SETUP);
GAME_RUN = new StateGameRun(this);
aState.push(GAME_RUN);
currentState=aState[enumState];
intervalVal=setInterval(Delegate.create(this,runGame),25);
}

function runGame() {
currentState.run();
}

function getTimeLine():MovieClip {
trace("getting timeLine value");
return mainTL;
}

function nextState() {
enumState++;
currentState=aState[enumState];
}

}//end class
[/cc]

The GameEngine class is actually pretty simple. First we import the classes we will need. We must import each state class we will use in our game and also the parent State class. We also need to import in the Delegate util class because we need to be able to maintain the scope of our function when we create an interval to run our loop inside another function. The constructor takes the main timeline in as a parameter, and then creates and instance for each state needed. It then pushes each state into an array of states called aState. It sets the currentState to enumState (which is 0) and then in creates an interval to call "runGame" repeatedly.

RunGame calls the run method of the current state. The getTimeLine() function is used by the individual states ifn they need access to the main timeLine. The nextState function is called by the individual states when they have completed their tasks.

That's if or our game loop. It really does nothing more than act as a controller for enumeration through all of the game states. The nextState function can use more logic when it gets to the final state in the array. This will be game specific.

The State Class

[cc lang="javascript" width="550"]import com.game.GameEngine;

class com.game.State {
var gameEngine:GameEngine;
var isComplete:Boolean=false;

function State (engineVal:GameEngine){
trace("super called");
gameEngine=engineVal;
}

function run() {
}

function completed() {
trace("completed called");
gameEngine.nextState();
}

}// end class
[/cc]

This is the parent class for our individual states. It enforces that each state subclass has a reference to the GameEngine, contain the isComplete Boolean, and a completed() function. Also, run() function has been added to remind the subClass programmers to implement one or the class will be useless.

The state sub classes:

[cc lang="javascript" width="550"]import com.game.GameEngine;

class com.game.StateGameSetUp extends com.game.State{
var mainTL:MovieClip;

function StateGameSetUp (engineVal:GameEngine){
super(engineVal);
mainTL=gameEngine.getTimeLine();
}

function setUpScreen() {
trace("setting up screen");
mainTL.setup_txt.text="complete";

isComplete=true;
}

function run() {
trace("isComplete=" + isComplete);
if (!isComplete) {
trace("setUpScreen called");
mainTL=gameEngine.getTimeLine();
setUpScreen();
}else{
trace("setUpScreen complete");
super.completed();
}
}

}// end class

import com.game.GameEngine;

class com.game.StateGameRun extends com.game.State{
var mainTL:MovieClip;

function StateGameRun (engineVal:GameEngine){
super(engineVal);
mainTL=gameEngine.getTimeLine();
}

function run() {
if (!isComplete) {
trace("StateGameRun called");
mainTL.run_txt.text="running";
}else{
trace("StateGameRun isComplete");
mainTL.run_txt.text="complete";
super.completed();
}
}

}// end class

[/cc]

These two classes are used to demonstrate examples of sub classing the State class. The StateGameSetUp class sets up the initial screen, sets its isComplete var to true and then calls the super's completed() function, which in turn calls gameEngine.nextState() function. The StateGameRun class runs until its isComplete is set to true. For this example, the game runs indefinitely.

That's it for our simple implementation. Download the .fla and class files to have a look. Obviously, I have left some questions unanswered. For example, what happens when you want the GameEngine to loop back to a state other than the next state when one is complete? There are a couple ways to handle this in my pattern. One would be to give each state instance a variable called "nextState()" and have it hold a reference to the next state to call. That would require some logic changes to the GameEngine and to the State class. Another way would be for the nextState() method of the GameEngine to handle the logic for the next state internally and have the nextState() method's logic contain a switch statement based on a Boolean value. Again, the more switch statements you use, the uglier the code will eventually be. Another alternative would be to use a sub-state pattern. This is the method I would choose for the simple implementation. If for instance, If wanted the StateTitleScreen and StateHighScore screen to alternate, I could either make one StateAttractMode and have it contain its own state machine for both of these only.

game1.swf (2007)
A demo of using Advanced Flash 8 Game Programming: A Finite State Machine Game Loop code.

Not much to see here except that the individual state status is displayed.

Downlod the examples files to check it out further.

download the zip file of classes and the .fla

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.

This site is protected by Comment SPAM Wiper.