A Finite State Machine (often abbreviated as "State Machine" or "FSM") is a system which manages the current state of an object and the other states it can be in. For example, a treasure chest can either be open or closed; that's only two states so you might not bother setting up a full FSM for something that simple. But a character often has many states such as idle, walk, run, jump, fall, attack, and so on, therefore a FSM will often be a good choice for managing that behaviour.
Many of the problems with Unity's Animator Controller system come from the fact that it is both an animation system and a state machine system combined, which limits its usefulness for either task. That's why Animancer's FSM system is entirely separate from the animation system. They work well together, but you can easily use one without the other if you want to.
There are plenty of other FSM systems available online (including on the Unity Asset Store), or if you're interested in implementing your own system Unity has a tutorial series about building a Pluggable AI With Scriptable Objects which could easily be adapted for other purposes.
The main core of the system is made up of 3 scripts:
|An interface with two properties (
CanExitState) that determine whether a particular state change will be allowed and two methods (
OnExitState) which notify the state when such a change occurs.
|Basically just a reference to an
IState with methods for accessing it and trying to change the state according to the properties in that interface.
|Used for accessing the previous and next state during the
IState methods. See Changing States page for more information.
Animancer.FSM was designed to achieve the following goals:
|The system does no more than necessary to enforce the state change rules so it has extremely good performance.
IState only has the bare minimum of members required for an FSM so you don't need to implement unneeded functions in basic scenarios and
StateMachine<TState> lets you manage states on-demand rather than pre-registering them all with their own Keys.
|You define your own base state type to suit your needs. For example, it does not automatically give every state an
Update function, but if you put one in your base state type you will be able to call
stateMachine.CurrentState.Update() as necessary. Or if you use State Behaviours you can use the regular MonoBehaviour Messages like
|States can be anything:
ScriptableObjects, or regular C# classes. All they need to do is implement
IState or inherit from one of the other State Types.
|The source code is included as plain scripts in both Animancer Lite and Pro so you can easily debug logic issues (one of the main Problems with Animator Controllers is that it's impossible to effectively debug their internal logic).
|This system is entirely separate from the rest of Animancer and barely even references anything from Unity so it could easily be ported to any C# environment outside of Unity.
There are two main areas where the restrictive nature of Animator Controllers actually gives them distinct advantages over this system:
Needing to define all your states and transitions in a single Animator Controller means it can show the way they are connected where a script based system like this allows any state to interact with any other state based on any kind of transition conditions. But in practice, this just gives you something to look at (usually a very messy something) without actually providing much useful information. Even if you can see a transition and look at its conditions, you still need to find the script that sets those parameters to figure out how it works.
Since all the states, parameters, and transitions in an Animator Controller need to be defined upfront, the current state identifier and parameter values can be easily sent over a network for another computer to lookup the correct state and apply those parameter values.
But since Animancer's animation system and this FSM system only need to know about a state when it is actually used, there is no identifier or common set of parameter values that could be sent over the network or used to lookup the corresponding details on another computer.
And even if animations did have an identifier, there would be no point in having a character play an Attack animation if the scripts on that computer don't actually know that the character is attacking. That's not a problem with Animator Controllers because they operate on their own internal logic so your scripts already need to be constantly checking what state it's in. But Animancer doesn't do any decision making for you, it only plays what you tell it to so your scripts can know what's playing without needing to check.
That doesn't mean Animancer and its FSM system can't be used in networked games, it just means they can't do the work for you automatically. If you use a Keyed State Machine where you register all your states on startup with an enum as the key, then you will be able to send the key over the network for the other computer to lookup the appropriate state. This means networking with Animancer is basically the same as networking any other script.