Finite State Machines in Unity
There are many different solutions to managing finite state machines in Unity. I don’t intend to comment here on the goodness of any other solutions — the best solution is the one that works for you. I just want to tell you about how I manage state machines. If you find it useful please go ahead and copy me and if you have any suggestions for how to improve on this technique please tell me.
There’s two parts to this, what I do and how I do it. All the code is available on Github if you would like to use it.
Components as States
The basic principle in my approach to state machines is to encapsulate each state in one or more components on the game object. There are two reasons for this
- As a component, each state has full access to all the standard messages and other features of Unity’s API.
- The state of a game object exists intrinsically in its components, so the natural way to change a game object’s state is to change its components.
I started off with the idea that each state is a component of the game object that the state machine exists on, which is clean and simple, but more recently I wanted more flexibility so now each state can comprise multiple components, and the components don’t have to be on the same game object as the state machine (although usually they are either there or on a child game object).
To implement this I have a single custom state machine component which manages the states, adding and removing components when entering and exiting states, and not much else.
Why it’s not straightforward
There was always a little wrinkle in this plan — components can’t exist outside of the game object on which they are created, so you can’t remove a component from a game object and then add it back later, removing it destroys it. It’s often desirable to maintain the internal data of a state when exiting it and re-entering it later so destroying the state component when exiting the state and creating a new one when re-entering it won’t work on it’s own. Over time I’ve used two different solutions for this.
When I first used components as states I was using Unity 3.5 and to keep things simple I would disable and enable components when changing state. The components for all the states existed on the game object all the time, and all but the current state were disabled. This works in most cases — the update methods don’t run on disabled components, and the OnEnable and OnDisable methods will be called when entering and leaving the state. However some specific messages are still received on disabled components - OnCollisionEnter for example - so I had to be a bit careful with this technique.
When Unity 5.3 was released it included the new JsonUtility class which provides a standard way to serialise objects, so since then I have serialised and removed components when leaving a state and deserialised and added them back when entering a state.
There is still a slight annoyance with this technique - it’s not possible to deserialise a component when creating it, instead you have to create a new instance and deserialise the old data into the new component. Because of this you have to avoid using the Awake and OnEnable methods in the state components because these methods are called before the deserialisation. The only initialisation method you can use in each state is the Start method, but I can work with that.
The StateMachine component has two configurable public properties, an array of states and the name of the initial state. Each state in the array has a name and an array of components for that state.
There is another public property which is the name of the current state, and a public method ChangeState(string) which takes the name of the new state as the parameter. On the surface there’s not much more to it than that. You could add more features but I’ve never needed them.
The StateMachine component also contains a bunch of private methods to handle the serializing and deserializing of the components and, like I said, there is a custom inspector for the class to help with the configuration.
To use it
- Drop the StateMachine class on a game object.
- Add all the components for all the states into the scene and configure them how you wish.
- Configure the states in the StateMachine instance with the names of the states and references to the component instances for each state.
When you enter the scene the components for all the states will be serialized and those not associated with the initial state will be removed. If you call ChangeState on the state machine then the components for the old state will be removed and the components for the new state will be added.
A component can be used in multiple states. If a component is in both the old and new states it is unchanged, it is not removed and re-added.
That’s all. If this is useful for you do let me know, and if you implement any improvements to it I would like to see them.
Have fun making your games.
Also in the collection Unity Game Engine