A state machine that try to be compatible with every use case possible.
Tested and working Unity 2021.3.1f1 (LTS)
If you see anything that not working, seems not right or missing, don't esitate to tell me.
This state machine is generic because of the possibility to drag and drop scripts in the inspector if you want to create a buffer or if you want to limite the possibilities of states the state machine can take.
In code you juste need to give a type to a function for it to change or add the state of the said type state.
You can have access to variables from states via a componant attatched to the state machine.
The state machine have currently two modes :
Single : the state machine can have only one state and change state exit the current one.
Stackable : Stack-based state machine.
The state machine can have a stack of states and add on top or go back.
Scripts are inside "GenericStateMachine" namespace.
First you will need to add the component "StateMachine" to the gameObject you want.
- Variables : A referance to the StateVariables component (see here)
- State Machine Type : The state machine type (single or stack-based). (see here)
- Changing state skip : If true, when changing state the state machine skip the end of the current frame.
- Can have any states : If true, this state machine can have any kind of state (Can't be true at same time as caching).
- Caching states : If true, states in Possible states are going to be created at awake of the state machine (not active).
- Starting state : This state will automatically be set at the awake of the state machine (can be null).
- Possible states : Used with Caching states (for knowing wich state need to be cached) and Can have any states (if false)
public State ChangeState(Type type);
public State ChangeState<T>();
Single mode : Change the current state.
Stackable mode : Same as AddState(type).
Return : The new state
public State AddState(Type type);
public State AddState<T>();
Single mode : Same as ChangeState(type).
Stackable mode : Set the current state to pause and add a new one of "type".
If cache activated resume if it already is in the previous states.
Return : The new state
public State RemoveState();
Single mode : Set the state to null.
Stackable mode : Remove the current state and resume the previous one.
Return : The new running state.
public void Clear();
Single mode : Set the state to null.
Stackable mode : Remove all states and set the state to null.
public bool Pause();
Pause the current running state.
Return : If the state was playing and well paused.
public bool Resume();
Resume the current running state.
Return : If the state was paused and well resumed.
public int GetStatesCount();
Get total number of states.
Return : Single mode : If no current state 0 else 1.
Stackable mode : number of states.
public List<string> GetStatesAsString();
Get states list.
Return : A list with all state as string (in order).
public List<Type> GetStatesAsType();
Get states list.
Return : A list with all states as System.Type (in order).
public State GetCurrentState();
Get the current running state.
Return : The current running state.
This component is automatically added with State machine, it can be removed and place in another Object and re-linked. State Variables component is here to give access at scripts / objects for states.
It is basically a list with a name and a reference of any type of object.
- Name : To be found when using
Get<T>("name")
method - Value : The reference you want, can be anything derived from UnityEngine.Object class (every component and more).
State an abstract class that you will need for every state.
using GenericStateMachine;
public class YourStateName : State
{
// Add your overrides here.
}
The state class have base methods you can override :
- Init : Called when a state is created (not cached called when you add or change state / cached called when a state is created in the cache (awake state machine))
- Enter : Called when entering a new state (ChangeState() and AddState())
NOTE : if the state machine is in stack-base mode and caching : when the state is more than one time in the stack it calls Resume(). - Exit : Called when the state is "removed" from the state machine.
NOTE : if the state machine is in stack-base mode and caching : when the state is more than one time in the stack it calls Pause(). - Resume : Called when Resume() method from state machine is called or when the state is back to the top (stack-base)
- Pause : Called when Pause() method from state machine is called or when the state is no more at the top (stack-base)
- PreUpdate : Called every frame just before the state Update().
- Update : Called every frame (Unity Update).
- LateUpdate : Called every frame (Unity LateUpdate).
- FixedUpdate : Called when the physics update (Unity FixedUpdate).
- RegisterInput : Called inside base.Enter() and base.Resume().
- UnregisterInput : Called inside base.Exit() and base.Pause().
You can have access to the state machine owner of the state via the public variable stateMachine
.
The idea of this project pop out after watching some codes and observed people and also myself, alwase create a new state machine script for every behaviour (principaly when caching states).
This project was create by myself after 9 months of practice in C# and unity.
- Make a state machine generic enough to not have to create multiple scripts for each state machine.
- Make the user set a sort of "Type" in the inspector : Use MonoScript.
- MonoScript are not usable outside the editor : Get the type from string and use reflection.
- Reflection in C#.
- Editor scripting in unity.
- Make a decent documentation.