Simple state machine on Unity
- Transfer
During development, we needed a simple state machine, preferably already implemented. From the list of implementations that Google suggested, this one was chosen for its simplicity and compactness. We use it ourselves, in general, FSM is not bad. Further, under the cut, the translation of the original article of the author from Greece Tasos Giannakopoulos. I am not a translator, so I tried to convey the meaning, sometimes explaining the essence in my own words, for which I apologize to perfectionists.
A state machine is a popular design pattern that game developers use to implement behaviors, such as the behavior of units or some complex objects.
A state machine (Finite state machine or FSM in bourgeois terminology) is easily described by diagrams and then programmed, which allows it to be used to implement a wide range of behaviors.
According to the definition of the AI-depot.com site (the best AI site, according to the author of the original article), a state machine consists of four main elements:
- states that determine behavior and can perform actions
- state transitions that determine the transition from one state to another
- terms and conditions that must be met for the transition
- input states received from the outside or from the inside, which, according to the rules, can lead to the transition of states.
I will not go into the theory of finite state machines, who needs it - there is the Internet with a bunch of detailed articles, and there are also several links at the end of the article.
To implement the behavior of the main character, in the project I'm working on now, I used FSM. Implementation in C #. At the moment, the code is far from its final form, but it has basic functionality, which is enough to explain the principle of FSM operation.
- Initialization of the state machine and a set of transitions that determine the character's behavior
- When input events arrive, an attempt is made to put the FSM in the appropriate state
- If a transition is possible, the state changes and a callback is called for the corresponding transition
In general, I wanted something that would allow me implement the following scheme, which determines the behavior of the player’s character. In addition, I would like the system to be extensible and new states and transitions could be easily added.
I looked, thought, and decided that in C # this task is best solved with the help of delegates. Delegates in C # are pointers to functions, which allows you to call a function from anywhere. They are easy to use, flexible, and most importantly they work quickly (this is almost a direct function call).
In the class diagram above, you can see StateTransition that is implemented through the IEquatable and FiniteStateMachine interface, the actual state machine interface itself. Both classes are templates that allow the user to determine the state. I use them with enums, which allow you to define a list of possible states.
StateTransition is essentially a C # tuple, where a value for two states is generated as a key. After I already implemented, I found out what can be done easier - implement through System.Collections.Generic.KeyValuePairwhere K and V are possible states. But since I'm not sure that switching from a tuple to KeyValuePair will give a speed boost, I decided to leave it as it is.
At the end of the article you will find a link to the sources of my implementation. Just unzip it and use as in the example below. I have already said that FSM is far from complete, but it provides basic functionality, and can be a starting point for other projects.
To get started, create an enumeration of all the states of your object and pass them to FiniteStateMachine.
You have to create a bunch of functions that implement the behavior of your object, for example, I have Run (), Idle (), IdleJump () and others. Then use AddTransition () to add the desired state transitions. Under certain conditions, you call Advance () in order to try to switch to the desired state. If a transition from the current state is possible, a function defined by the user is called.
The code below implements part of my character’s behavior. This piece of code is enough to understand how to use FSM.
FSM source
https://en.wikipedia.org/wiki/Finite-state_machine
http://ai-depot.com/FiniteStateMachines/FSM.html
http://jessewarden.com/2012/07/finite-state-machines-in- game-development.html
http://unitygems.com/fsm2/
Author of the original article: Tasos Giannakopoulos .
What is a state machine?
A state machine is a popular design pattern that game developers use to implement behaviors, such as the behavior of units or some complex objects.
A state machine (Finite state machine or FSM in bourgeois terminology) is easily described by diagrams and then programmed, which allows it to be used to implement a wide range of behaviors.
According to the definition of the AI-depot.com site (the best AI site, according to the author of the original article), a state machine consists of four main elements:
- states that determine behavior and can perform actions
- state transitions that determine the transition from one state to another
- terms and conditions that must be met for the transition
- input states received from the outside or from the inside, which, according to the rules, can lead to the transition of states.
I will not go into the theory of finite state machines, who needs it - there is the Internet with a bunch of detailed articles, and there are also several links at the end of the article.
Why all this?
To implement the behavior of the main character, in the project I'm working on now, I used FSM. Implementation in C #. At the moment, the code is far from its final form, but it has basic functionality, which is enough to explain the principle of FSM operation.
- Initialization of the state machine and a set of transitions that determine the character's behavior
- When input events arrive, an attempt is made to put the FSM in the appropriate state
- If a transition is possible, the state changes and a callback is called for the corresponding transition
In general, I wanted something that would allow me implement the following scheme, which determines the behavior of the player’s character. In addition, I would like the system to be extensible and new states and transitions could be easily added.
Design and implementation
I looked, thought, and decided that in C # this task is best solved with the help of delegates. Delegates in C # are pointers to functions, which allows you to call a function from anywhere. They are easy to use, flexible, and most importantly they work quickly (this is almost a direct function call).
In the class diagram above, you can see StateTransition that is implemented through the IEquatable and FiniteStateMachine interface, the actual state machine interface itself. Both classes are templates that allow the user to determine the state. I use them with enums, which allow you to define a list of possible states.
StateTransition is essentially a C # tuple, where a value for two states is generated as a key. After I already implemented, I found out what can be done easier - implement through System.Collections.Generic.KeyValuePair
At the end of the article you will find a link to the sources of my implementation. Just unzip it and use as in the example below. I have already said that FSM is far from complete, but it provides basic functionality, and can be a starting point for other projects.
How to use
To get started, create an enumeration of all the states of your object and pass them to FiniteStateMachine.
// Add the possible states here
public enum eCharacterState
{
IDLE,
RUN,
// ...
};
public class CharacterFSM : FiniteStateMachine {};
You have to create a bunch of functions that implement the behavior of your object, for example, I have Run (), Idle (), IdleJump () and others. Then use AddTransition () to add the desired state transitions. Under certain conditions, you call Advance () in order to try to switch to the desired state. If a transition from the current state is possible, a function defined by the user is called.
The code below implements part of my character’s behavior. This piece of code is enough to understand how to use FSM.
public class Player : CatGameItem
{
// ...
public CharacterFSM mFSM;
void Start ()
{
mFSM = new CharacterFSM();
// Add state transitions here
mFSM.AddTransition(eCharacterState.IDLE, eCharacterState.RUN, Run);
mFSM.AddTransition(eCharacterState.RUN, eCharacterState.IDLE, Idle);
// This calls the Run() function while on run state.
// I will probably replace it with with a state callback or something similar sometime in the future to avoid calling TryGetValue all the time.
mFSM.AddTransition(eCharacterState.RUN, eCharacterState.RUN, Run);
// ...
}
// FSM Delegates
void Run()
{
//Debug.Log("RUN!");
float curMoveSpeed = Controller.GetGroundSpeed();
AnimationController.SetSpeed("Cat_Run", curMoveSpeed/RunSpeed);
AnimationController.Play("Cat_Run");
}
void Idle()
{
AnimationController.Play("Cat_Idle_Breath");
}
// ...
void UpdateInput()
{
mCurAxisInput.x = Input.GetAxis("LeftAxisH"); // Get Horizontal axis (XBox360 xAxis OR 'A', 'D')
mCurAxisInput.y = Input.GetAxis("LeftAxisV"); // Get Vertical axis (XBox360 yAxis OR 'W', 'S')
}
void UpdateStateMachine()
{
// Based on the input events, advance to desired state
// Run, Idle
if (mCurAxisInput.magnitude > 0)
mFSM.Advance(eCharacterState.RUN);
else
mFSM.Advance(eCharacterState.IDLE);
// ...
}
void FixedUpdate()
{
// Update the state machine here
UpdateStateMachine();
}
void Update ()
{
// Update user input
UpdateInput();
UpdateCharacterMovement();
}
}
FSM source
Links to related articles:
https://en.wikipedia.org/wiki/Finite-state_machine
http://ai-depot.com/FiniteStateMachines/FSM.html
http://jessewarden.com/2012/07/finite-state-machines-in- game-development.html
http://unitygems.com/fsm2/
Author of the original article: Tasos Giannakopoulos .