Sunday, March 27, 2011

Simple FSM

'Finite state machines' are the heart of every game, and have been around for a very long time without you even noticing it. Ever played Pac-Man ? Well, it had a FSM (simple one, but still).

A finite state machine is a set of states with transitions between them. For example let's try to make a FSM representing a cat. The cat can sleep, wander around, go eat and run from danger. Then a sleeping cat could only wake up and start wandering around. It could fall back to sleep again but it could also go eat or run from a nearby dog. Take a look at the diagram:


To go from one state to another, we need to have a condition and depending on that condition we'll chose what state we should go to. The text over each arrow shows the transition condition. It is very simple to expand that FSM to make a smarter cat provided all transitions are properly made.

Each state defines a certain number of actions that are made when a new state is entered. This way we can create specific behaviors for each state as seen in the cat example above. 'Eat' state would be take food, chew, sallow and take food again until no more food.


In video games, state machines are used everywhere: 
  • artificial intelligence: create autonomous agents for realistic behaviors, like an Unreal bot who can shoot you, then run away towards a medpac, then find ammunitions and finally hunt you again;
  • cameras: switch between a top view camera to right shoulder camera when aiming at something;
  • game states: menu state, option state, in-game state;


Now, this whole thing was to introduce you to the implementation I made. I don't think it's the best FSM ever created, I'm sure there a things I could do to make it better but it's far enough for the uses I've made so far.

To start we have two abstract classes: FSM which holds the current state and CState which defines the states process (they serve as an interface only). The state machine you want to create must derive from FSM and it's states from CStates. The states it should accept should only be the ones associated with that FSM to avoid mixing states from two distinct machines. That's why the ChangeState should take as argument the associated state class instead of the general CState class. See diagram:


This way we can create tons of state machines all independent from each others and having them well organized.
Using this method, the change of state calls a new and delete operator which can be troublesome if too many calls are made. Another method could be using templates instead of arguments and casting the current state but casting can also take lots of resources...Still looking at that.
I'm not showing code here because I simply don't think there is anyone reading this, I just don't think code's hard to write (unless I've explained myself as bad as the 9/11 explanations...)  and also because copy-pasting code is the nemesis of all programmers.

On last thing. If you ever played Starcraft II, you've probably noticed that a unit in it's 'Hold position' mode (all modes are states) will move to a target unit nearby if any, kill it and then fall back to the exact same location it was before attacking. This is possible thanks to stacked state machines.
A stack state machine is a state machine like any other, keeping track of the previous state it was. Doing so we can fall back from one state to one of the previous states if needed, keeping the state data.


Hopefully it was clear and without mistakes. Yes, since potential employers might read this, it would be silly to shoot myself on the foot :)

0 comments:

Post a Comment

Popular Posts

Blog Archive