using System.Collections; using System.Collections.Generic; using UnityEngine; using ZelleGames.Log; namespace ZelleGames.StateMachine { /// /// Generic abstract state machine with OnEnter and OnExit features /// public abstract class StateMachine : MonoBehaviour { /// /// Readonly State currently executing /// public State CurrentState { get; protected set; } /// /// Drive the current state if present /// private void Update() { if (CurrentState != null) { CurrentState.Update(Time.deltaTime); } } /// /// Drive the current state's FixedUpdate method if state is present /// private void FixedUpdate() { if (CurrentState != null) { CurrentState.FixedUpdate(Time.fixedDeltaTime); } } /// /// Public facing function to change state based on a transition. /// Relies on an implementation of /// /// The transition to pass in. Validitiy depends on the implementation of GetNewState public void TransitionState(Transition t) { var newState = GetNewState(t); if (newState != null) { CurrentState?.OnExit(); CurrentState = newState; CurrentState.StateMachine = this; CurrentState.OnEnter(); } else { Logging.Log(LogLevel.WARN, $"Could not transition from {CurrentState} with {t}"); } } /// /// Load a new state without consideration of the GetNewState function. /// This is sessentially the "goto" of state machine management, use only if absolutely needed. /// /// public void ForceState(State s) { CurrentState.OnExit(); CurrentState = s; CurrentState.OnEnter(); } /// /// Derived classes should provide an implementation that returns a new depending /// on the Transition passed in. /// /// /// The new state for a valid transition for the current state, /// Null otherwise to maintain current state protected abstract State GetNewState(Transition t); } /// /// Transitions are passed into the state machine to move from one state to the next. /// public abstract class Transition { /// /// Generic object that can contain any information this transition needs to pass into the next state /// public object Context { get; } public Transition() : this(null){} public Transition(object ctx) { Context = ctx; } } /// /// Describes a finite state for a /// in Unity. /// public abstract class State { /// /// Reference to the parent statemachine. Derived classes can cast this reference into their specialized /// class for specific statemachine functionality, or use this reference as is to operate on the base class /// public StateMachine StateMachine; /// /// Called every frame by the /// /// public abstract void Update(float deltaTime); /// /// Called according to the Physics timing configuration by the /// /// public virtual void FixedUpdate(float fixedDeltaTime) { } /// /// Called on the frame the machine switches to this state /// public virtual void OnEnter() { } /// /// Called on the last frame before this state is replaced. /// public virtual void OnExit() { } } }