Game AI is one of the main reasons people will continue to play a game again and again. Games without good AI tend to lack any replay value. An example of really bad AI is Aliens: Colonial Marines. Just check out this video of someone playing on ‘Hardened’ difficulty and not even needing to shoot the enemy Aliens.
In this article, I am going to explain how to use FSM for game AI. FSM or Finite State Machines are a mathematical model of computation. This means that an entity can only exist in a number of states which then moves to another state based on some input. A simple example of this is a light bulb. A lightbulb can be in 2 states: on and off. If the switch is turned on then the light changes to the on state, the if the switch is switched off the light moves to the off state.
Another example relating to games could be an AI enemy character in a platformer, he could be in any of the following states: running, jumping, standing, falling, seeking, fleeing, wandering etc. While the AI enemy is in the standing state he can be looking for an enemy, if no enemy is found he can move to the wandering state which makes him wander around a bit then puts him back in the standing state looping until an enemy is found. Once an enemy is found he can move to the seeking state which makes him move towards his enemy. In the seeking state, we can have some conditionals for health and distance from the enemy. If health drops below 10% move to the fleeing state and if Distance from the enemy is close enough to attack then do some damage and on and one and so forth.
How do we use an FSM in a game?
For the purpose of this article, I’m going to explain how to do this in pseudo code to allow you to implement it in your own favoured programming language. I will create an FSM for a farmer who can be in 4 states: farming for food, sleeping for fatigue, eating for health and storing food. Our first part will be to create the different states we need each with their own entering, exiting and while in sections.
Farming (
When Entering: move to farm.
move to farm.
While in state: gather food
add 1 to fatigue
if inventory full change to Storing state
if fatigue maxed out change to Sleeping state
When exiting: do nothing.
do nothing.
)
Sleeping (
When Entering:
move to home
While in state: sleep (lower fatigue a bit)
sleep (lower fatigue a bit)
if hunger > 50% move to Eating state else
if fatigue has all gone change to Farming state
When exiting:
say “ah all refreshed”
)
Eating (
When Entering: Move to home
Move to home
While in state: remove 1 food from store
remove 1 food from store
remove 1 food from store
remove 1 food from store
lower hunger
if hunger is 0% change to Farming state
When exiting:
say “Yummy that was tasty”
)
Storing (
When Entering:
move to store
While in state:
remove 1 inventory food and place in storage
if 0 food in inventory then move to the farming state
When exiting:
say “Stored all my food”
)
Now we have all of our states and the code they will use we need to make it so our character starts in a state and then updates states. In our character’s constructor or initialization we add
character set state sleeping
This sets our character to a state that they start in. Now where the logic of our game takes place we add
if current state equals the previous state then
do current state’s ‘do while code’
else
do previous state’s ‘When exiting code’
do current state’s ‘When entering code’
set ‘previous state’ to ‘current state ‘
This allows our character to change states and run the ‘when entering’ and ‘when exiting’ code. Our character should have 4 variables, one for hunger and one for fatigue which is used to flag when a state should be changed and current state and previous state which is used to determine if a state has just been entered or left.
Finite State Machine Limitations.
FSM are good for characters that have a defined set of states and change based on a few set of inputs. They are not good when used on characters that have a lot of input variables and many possible states. If your characters in your game have many inputs and many set states you could possibly use behaviour trees. A nice guide on what behaviour trees are is located here on the libgdx wiki.