Let’s see how to implement a basic AI with the FSM pattern…
This article is also available on Medium.
This tutorial is available either in video format or in text format — see below 🙂
About Coding AI
When you develop games, you’ll often need to give your characters and monsters a very basic form of intelligence so that they can patrol around, chase your hero or even mimic more complex human behaviours and replace a real opponent during training. Over the years, people have invented lots of architectures to simulate this artificial intelligence that each have their advantages and drawbacks.
If you want to learn more about these various techniques to implement AI, you should definitely read this amazing article by Dave Mark from 2012 that explains how you put brains in your game… based on tacos and tostadas! 😉
The FSM pattern
Today, I’m going to focus on a well-known AI pattern: the finite state machine, or FSM. Roughly put, FSMs work as follows:
- you have a finite set of states that your entity can be in
- you define transitions to switch between those states that can be triggered in various ways
- and so the entity has an active state that is initialised to a default state and can then change throughout its lifetime thanks to these transitions
It’s usually a quick way of modelling simple AIs that have a limited number of actions and a deterministic behaviour.
There are multiple techniques to implement this pattern in your game: for example, you can create one C# class per state and encapsulate all the logic and the data relevant to this state in this class. If you want a more in-depth example of FSMs, and if you want to see how to apply this multi-class technique, make sure to check out this other video I made on state machines.
Designing our FSM structure
But, when your AI is really simple, you can actually stick with just one class and use an enum to define your different states.
Then, you just need to keep the current state in a variable, set it to the default state at the beginning, and check what your current state is in the
Update() to know what logic to run.
Here, let’s say my character has three possible states:
- Idle: that’s for when it’s not doing anything – that’s the default state and it will remain in this state until a coin pops and triggers a transition
- if the character finds a target (be it a coin, the chest or the initial position), then it will enter the MoveTo state and aim at that target until it’s reached it
- finally, if the character has picked up a coin, it will stop for just a second and go to its Dance state, long enough to perform a little dance of victory, before resuming to its MoveTo state and bringing the coin to the chest
By the way, this means that I have two types of transitions: conditional and unconditional. For example, going from Idle to MoveTo is conditional, it will only happen if there is a coin in sight; but going from Dance to MoveTo is unconditional, the state machine will simply wait for the time of the dance animation.
Also, the only difference between moving to a coin, to the chest or to the initial position is what happens at the very end of the move, when the character reaches the target. So we can actually prepare a global logic for all these moves and use a C# delegate to handle the specific logic when we reach the target.
Then, to move my character, I’ll need a reference to its CharacterController component. I’ll also add a reference to its Animator so that I can switch to another animation along with my FSM state:
Note: if you want to learn more about animations and Animators, you can take a look at this tutorial I made recently on how to animate a Mixamo character in Unity.
Now, in my
Update(), all I have to do is call the
_MoveTo() function if I’m in the MoveTo state. Similarly, if I’m in the Dance state, I’ll call the
_Dance() function. The Idle state doesn’t run any logic.
Implementing the logic
Ok now that I have the structure of my state machine, it’s time to fill these methods and do some transitions!
_MoveTo() will simply compute the direction to the target position and either move the CharacterController towards it or call the
OnReachTarget delegate if the point is close enough:
Then, each delegate will do a different thing.
When we reach a coin, we want to destroy the coin game object, switch to the Dance state and look at the camera:
When we reach the chest, we want to increase the coin counter (for example using an event from a global
UIManager) and aim back for the initial position:
When we reach the initial position, we want to tell the Coin Spawner script we are ready for a new coin (with another event), go back to the Idle state and look at the camera:
Finally, in the
_Dance() method, I’ll have a little counter that checks whether I’ve exceeded the duration of the dance animation (in my case, this animation lasts just over 2 seconds). When this delay has elapsed, I need to switch back to the MoveTo state and go to the chest:
Also, I need to make sure to reset this
_danceDelay in the
_OnReachCoin() delegate so that, next time, the state machine waits for the animation to complete once again:
The last step is to actually start all this sequence of actions with the initial trigger from Idle to MoveTo when a coin pops. To do this, we can use a SphereCollider to define the character’s field of vision and set it to be a trigger:
Then, we can head back to our script and use the
OnTriggerEnter() built-in function to start all of our logic:
And here we are! We now have a very basic AI that, thanks to the power of finite state machines, can auto-collect coins and dance! Pretty cool, right? 🙂
I hope you enjoyed this short tutorial – make sure to like and share it if you did! And of course, feel free to drop a comment with your idea for a future Unity tutorial 😉
As always, thanks a lot for reading and stay tuned for more articles on coding and games!