Skip to content

Instantly share code, notes, and snippets.

@DenL
Last active April 23, 2019 05:24
Show Gist options
  • Save DenL/7e89937f6ca546cc985fa758cf50d7f0 to your computer and use it in GitHub Desktop.
Save DenL/7e89937f6ca546cc985fa758cf50d7f0 to your computer and use it in GitHub Desktop.
A FSM implementation utilizing Unity Coroutine.
using System.Collections;
using UnityEngine;
namespace MochiLabs.FSM {
public interface IState {
void Link(StateMachine machine);
void Enter();
IEnumerator Executing();
void CheckParameter();
void Exit();
}
/// <summary>
/// A FSM State implementation using Unity Coroutine.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class State<T> : IState where T : MonoBehaviour {
protected T context;
protected StateMachine machine;
protected Coroutine coroutine;
public State(T context) {
this.context = context;
}
public void Link(StateMachine machine) {
this.machine = machine;
}
public virtual void Enter() {
if (context != null) {
coroutine = context.StartCoroutine(Executing());
}
}
public virtual IEnumerator Executing() {
yield return null;
}
public virtual void CheckParameter() {
}
public virtual void Exit() {
if (context != null && coroutine != null)
context.StopCoroutine(coroutine);
}
}
}
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using Sirenix.OdinInspector;
namespace MochiLabs.FSM {
/// <summary>
/// A FSM implementation using Unity Coroutine
/// </summary>
/// <typeparam name="T"></typeparam>
[Serializable]
public sealed class StateMachine {
[ShowInInspector]
public IState CurrentState { get; private set; }
private Dictionary<Type, IState> allStates = new Dictionary<Type, IState>();
private Dictionary<string, object> parameters = new Dictionary<string, object>();
public StateMachine(IState initialState) {
AddState(initialState);
EnterState(initialState);
}
public void AddState(IState state) {
state.Link(this);
allStates[state.GetType()] = state;
}
/// <summary>
/// Immediately exit old state and enter new state
/// </summary>
/// <param name="newState"></param>
public void ChangeState<S>(/*object caller = null*/) where S : IState {
Type newStateType = typeof(S);
if (!allStates.TryGetValue(newStateType, out IState newState)) {
Debug.LogError("State not added.");
/* Avoid reflection when possible, don't use
newState = (IState)(newStateType.GetConstructor(new[] { caller.GetType() }).Invoke(new[] { caller }));
AddState(newState);
*/
return;
}
if (CurrentState != null && CurrentState.GetType() != newStateType)
CurrentState.Exit();
EnterState(newState);
}
public bool CurrentStateIs<S>() where S : IState {
return CurrentState.GetType() == typeof(S);
}
public void SetParameter(string key, object value) {
parameters[key] = value;
CurrentState.CheckParameter();
}
public bool TryGetParameter<T>(string key, out T value) {
value = default(T);
return parameters.TryGetValue(key, out value);
}
private void EnterState(IState state) {
CurrentState = state;
CurrentState.Enter();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment