// Animancer // Copyright 2020 Kybernetik // using System; using UnityEngine; namespace Animancer.FSM { /// /// A simple keyless Finite State Machine system. /// /// This class doesn't keep track of any states other than the currently active one. /// See for a system that allows states to be pre-registered and accessed /// using a separate key. /// [HelpURL(StateExtensions.APIDocumentationURL + "StateMachine_1")] public partial class StateMachine where TState : class, IState { /************************************************************************************************************************/ /// The current state. public TState CurrentState { get; private set; } /************************************************************************************************************************/ /// /// Constructs a new . /// public StateMachine() { } /// /// Constructs a new and immediately enters the `defaultState`. /// public StateMachine(TState defaultState) { CurrentState = defaultState; defaultState.OnEnterState(); } /************************************************************************************************************************/ /// /// Checks if it is currently possible to enter the specified `state`. This requires /// on the and /// on the specified `state` to both return true. /// public bool CanSetState(TState state) { if (CurrentState != null && !CurrentState.CanExitState(state)) return false; if (state != null && !state.CanEnterState(CurrentState)) return false; return true; } /************************************************************************************************************************/ /// /// Attempts to enter the specified `state` and returns true if successful. /// /// This method returns true immediately if the specified `state` is already the . /// To allow directly re-entering the same state, use instead. /// public bool TrySetState(TState state) { if (CurrentState == state) return true; else return TryResetState(state); } /************************************************************************************************************************/ /// /// Attempts to enter the specified `state` and returns true if successful. /// /// This method does not check if the `state` is already the . To do so, use /// instead. /// public bool TryResetState(TState state) { if (!CanSetState(state)) return false; ForceSetState(state); return true; } /************************************************************************************************************************/ /// /// Calls on the then changes to the /// specified `state` and calls on it. /// /// This method does not check or /// . To do that, you should use instead. /// public void ForceSetState(TState state) { #if UNITY_EDITOR var owned = state as IOwnedState; if (owned != null && owned.OwnerStateMachine != this) { throw new InvalidOperationException( "You are attempting to use a state in a machine that is not its owner." + "\n State: " + state + "\n Machine: " + ToString()); } #endif if (CurrentState != null) CurrentState.OnExitState(); CurrentState = state; if (CurrentState != null) state.OnEnterState(); } /************************************************************************************************************************/ /// /// Returns a string describing the type of this state machine and its . /// public override string ToString() { return GetType().Name + " -> " + CurrentState; } /************************************************************************************************************************/ } }