(continues from page 1)
Before taking a look at the code, you should take a look also at the linked list and hashmap tutorials that we published some time ago on our design-nation website, because we will need them now.
We have implemented four classes:
- Transition (transitions)
- State (states)
- SMachine (state machine)
- BEngine (behaviour engine, it’s the one that manages all the game’s state machines)
Things will work the following way: first we’ll create the state machine that we are going to need, then we’ll add it its states and transitions, and then we’ll register that state machine in the global behaviour engine (BEngine). That behaviour engine will have a timer, so it will control the state machines execution.
First, we’ll take a look at this engine. To simplify, it’s just a list that holds a reference to each state machine that has been registered. So we can add new state machines to that list, remove a machine from it, etc.
class BEngine
{
private var machineListVal: List;
public function BEngine()
{
this.machineListVal = new List();
}
public function registerSMachine(machine: SMachine)
{
this.machineListVal.push(machine);
}
public function unregisterSMachine(machine: SMachine)
{
this.machineListVal.deleteElement(machine);
}
public function doProcess()
{
var it: IIterator = this.machineListVal.iterator();
while(it.hasNext())
{
SMachine(it.next()).executeCycle();
}
}
}
The state machine is not a collection with all the states and transitions. However, we hold only a reference to the first state and the current state. Why? Because the states will be linked by the transitions, so we don’t need to know all the states of the state machine, only the first one, and the current one (so we can evaluate its transitions). However, we have to know if the machine is running, or is stopped.
class SMachine
{
...
...
public function resetToInit(initState: State)
{
this.currStateVal= initState;
this.initStateVal= initState;
}
...
...
}
Each state will hold a callback and an array with a reference to all the transitions that start at that state.
class State
{
...
...
public function addTransition(transition: Transition)
{
if(transitionDoNotExist(transition))
{
this.transitions.push(transition);
}
}
...
...
public function evalState(paramater: Object): fgPair
{
var nextState: State = undefined;
var retPair: Pair;
var nTam: Number= this.transitions.length;
for(var nIx: Number = 0; nIx < nTam && nextState == undefined; nIx++)
{
var currentTransition: Transition = this.transitions[nIx];
if(currentTransition.evaluate())
{
nextState = currentTransition.endState;
retPair = new fgPair(nextState, currentTransition);
}
}
return retPair;
}
public function execute(parameter: Object): Object
{
return actionCallbackVal.fire(parameter);
}
...
...
}
And last, the transitions. Each transition holds a reference to the initial and the final state and has the ability to execute a callback.
class Transition
{
...
...
public function set initState(state: State)
{
state.addTransition(this);
this.initStateVal = state;
}
public function set endState(state: State)
{
this.endStateVal = state;
}
...
...
public function execute(parameter: Object): Object
{
return this.actionCallbackVal.fire(parameter);
}
public function evaluate(): Boolean
{
var retVal: Boolean = true;
if(this.evaluationCallbackVal != undefined)
{
retVal = Boolean(evaluationCallbackVal.fire(this));
}
return retVal;
}
...
...
}
And now, let's develop a game.
(continues on page 3)
|