Skip to content

Instantly share code, notes, and snippets.

@FlaShG
Last active August 21, 2022 15:15
Show Gist options
  • Save FlaShG/2ee7a3fd82b9068f3f76defc2c4d503c to your computer and use it in GitHub Desktop.
Save FlaShG/2ee7a3fd82b9068f3f76defc2c4d503c to your computer and use it in GitHub Desktop.
A simple state machine class for Unity. Use it to run regular methods or coroutines as states.
using UnityEngine;
using System;
using System.Collections;
/// <summary>
/// A simple state machine class. Use it to run regular methods or coroutines as states.
/// Steps to use:
/// 1. Define a private field for the StateMachine object.
/// private StateMachine stateMachine;
/// 2. Initialize the object in Awake. Pass the MonoBehaviour object to the constructor.
/// stateMachine = new StateMachine(this);
/// 3. Use SetNextState to pass either a void method or a coroutine as a state to the statemachine.
/// The state will run in a loop until SetNextSate is called.
/// The current state will come to an end, and the next state will be started in a loop afterwards.
/// </summary>
public class StateMachine
{
private MonoBehaviour owner;
private Action nextState;
private Func<IEnumerator> nextCState;
private bool nextStateIsCoroutine;
private bool running = false;
public bool isInThisState { get; private set; }
#region Constructors
public StateMachine(MonoBehaviour owner)
{
if (!owner)
{
throw new ArgumentException("You need to assign a MonoBehaviour to this StateMachine!");
}
this.owner = owner;
}
#endregion
#region State Setters and Helper Methods
public void SetNextState(Action state)
{
nextState = state;
nextCState = null;
nextStateIsCoroutine = false;
StateSet();
}
public void SetNextState(Func<IEnumerator> state)
{
nextCState = state;
nextState = null;
nextStateIsCoroutine = true;
StateSet();
}
private void StateSet()
{
isInThisState = false;
if (!running && HasNextState())
{
owner.StartCoroutine(Run());
}
}
private bool HasNextState()
{
return nextStateIsCoroutine ? (nextCState != null) : (nextState != null);
}
#endregion
private IEnumerator Run()
{
running = true;
while (HasNextState())
{
if (!owner)
{
Debug.LogError("The MonoBehaviour assigned to this StateMachine has been destroyed!");
running = false;
yield break;
}
isInThisState = true;
if (nextStateIsCoroutine)
{
yield return owner.StartCoroutine(nextCState());
}
else
{
nextState();
yield return null;
}
}
running = false;
isInThisState = false;
}
}
using UnityEngine;
using System.Collections;
/// <summary>
/// Example class for StateMachine.cs.
/// When in the idle state, pressing space triggers the fly state, which lasts for two seconds before returning to the idle state.
/// </summary>
public class StateMachineDemo : MonoBehaviour
{
private StateMachine stateMachine;
private void Awake()
{
stateMachine = new StateMachine(this);
}
private void Start()
{
stateMachine.SetNextState(IdleState);
}
private void IdleState()
{
if(Input.GetKeyDown(KeyCode.Space))
{
stateMachine.SetNextState(FlyState);
}
}
private IEnumerator FlyState()
{
// TODO Start upwards Movement
yield return new WaitForSeconds(2);
// TODO Stop upwards movement
stateMachine.SetNextState(IdleState);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment