using UnityEngine; using System; using System.Collections.Generic; public class SimpleStateMachine : MonoBehaviour { public bool DebugGui; public Vector2 DebugGuiPosition; public string DebugGuiTitle = "Simple Machine"; protected Enum queueCommand; void OnGUI() { if (DebugGui) { GUI.Box(new Rect(DebugGuiPosition.x, DebugGuiPosition.y, 200, 50), DebugGuiTitle); GUI.TextField(new Rect(DebugGuiPosition.x + 10, DebugGuiPosition.y + 20, 180, 20), string.Format("State: {0}", currentState)); } } protected float timeEnteredState; public class State { public Action DoUpdate = DoNothing; public Action DoFixedUpdate = DoNothing; public Action DoLateUpdate = DoNothing; public Action DoManualUpdate = DoNothing; public Action enterState = DoNothing; public Action exitState = DoNothing; public Enum currentState; } public State state = new State(); public Enum currentState { get { return state.currentState; } set { if(state.currentState == value) { return; } ChangingState(); state.currentState = value; ConfigureCurrentState(); } } [HideInInspector] public Enum lastState; void ChangingState() { lastState = state.currentState; timeEnteredState = Time.time; } void ConfigureCurrentState() { if (state.exitState != null) { state.exitState(); } //Now we need to configure all of the methods state.DoUpdate = ConfigureDelegate("Update", DoNothing); state.DoFixedUpdate = ConfigureDelegate("FixedUpdate", DoNothing); state.DoLateUpdate = ConfigureDelegate("LateUpdate", DoNothing); state.DoManualUpdate = ConfigureDelegate("ManualUpdate", DoNothing); state.enterState = ConfigureDelegate("EnterState", DoNothing); state.exitState = ConfigureDelegate("ExitState", DoNothing); if (state.enterState != null) { state.enterState(); } } Dictionary> _cache = new Dictionary>(); T ConfigureDelegate(string methodRoot, T Default) where T : class { Dictionary lookup; if(!_cache.TryGetValue(state.currentState, out lookup)) { _cache[state.currentState] = lookup = new Dictionary(); } Delegate returnValue; if (!lookup.TryGetValue(methodRoot, out returnValue)) { var mtd = GetType().GetMethod(state.currentState.ToString() + "_" + methodRoot, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod); if(mtd != null) { returnValue = Delegate.CreateDelegate(typeof(T), this, mtd); } else { returnValue = Default as Delegate; } lookup[methodRoot] = returnValue; } return returnValue as T; } void Update() { EarlyGlobalSuperUpdate(); state.DoUpdate(); LateGlobalSuperUpdate(); } void FixedUpdate() { state.DoFixedUpdate(); } void LateUpdate() { state.DoLateUpdate(); } protected virtual void EarlyGlobalSuperUpdate() { } protected virtual void LateGlobalSuperUpdate() { } static void DoNothing() { } }