Why?
When developing games, I often need FSMs. Most of the time, they are simple with only a few states. Some examples of state machines I used in previous or current games:
- Tutorial: each state represents a step in the tutorial
- UI : The animated elements are using a FSM to transition from “on-screen” to “off-screen” going through a “moving” state.
- Game State : Playing, Paused and End-of-level screens
Some complex FSMs are often used in AI. I used some in this prototype.
Features
I realized that I always implemented the same methods when adding a FSM into an object, therefore I took a few minutes to implement a simple class I could re-use easily. Here are the features of this FSM:
- The states are represented by an enum (easy to debug)
- To run the FSM, just call SetState and UpdateFSM( float delta_time )
- Get the current state using GetState()
- Many transitions are based on timing. Therefore, I implemented a GetTimeInCurState() method
- Perform your specific actions in methods BeginState, EndState and UpdateState
Source Code (.h)
// (c) Francois Guibert, www.frozax.com (@Frozax)
#pragma once
template<typename T>
class fgFSM
{
public:
fgFSM() : _time_in_cur_state(0.0f), _cur_state(-1)
{
}
virtual void BeginState( T state ) {}
virtual void UpdateState( T state ) {}
virtual void EndState( T state ) {}
void SetState( T state )
{
EndState( (T)_cur_state );
_cur_state = state;
_time_in_cur_state = 0.0f;
BeginState( (T)_cur_state );
}
void UpdateFSM( float delta_time )
{
if( _cur_state != -1 )
{
_time_in_cur_state+=delta_time;
UpdateState( (T)_cur_state );
}
}
float GetTimeInCurState() { return _time_in_cur_state; }
T GetState() { return (T)_cur_state; }
private:
float _time_in_cur_state;
int _cur_state;
};
Usage
First create the enum you will use for the states, such as:
enum EState
{
STT_OFF = -1, // optional, -1 is the initial state of the fsm
STT_WALK,
STT_RUN,
STT_STOP,
STT_EAT
};
And inherit from the class fgFSM:
class ObjectUsingFSM: public fgFSM<EState>
{
public:
// ...
void UpdateState( EState t );
void BeginState( EState t );
void EndState( EState t );
// ...
};
Improvements, Closing Words
That’s it, feel free to use the code in your games/projects. This is very simple but often more than enough. The other feature you might need one day is having a GetPreviousState() or even a GetNextState() usable in EndState().
Questions? Contact me on twitter @frozax or comment here.