using System; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; using UnityEditor.UIElements; #endif using UnityEngine; using UnityEngine.UIElements; namespace BITKit.StateMachine { [Serializable] public class MonoStateMachine : IStateMachine where TState : IState { public bool Enabled { get => _enabled; set { _enabled = value; if (CurrentState is null) return; if (value) { CurrentState.OnStateExit(null,null); } else { CurrentState.OnStateEntry(null); } } } public TState CurrentState { get; set; } public event Action OnStateChanged; [SerializeReference, SubclassSelector] public List states = new(); [SerializeField,ReadOnly] private string _currentStateName; [SerializeField] private bool debug; [SerializeField] private bool transitionOnNextFrame; public IDictionary StateDictionary { get; } = new Dictionary(); private bool _enabled = true; private readonly DoubleBuffer _nextState = new(); protected bool cancelUpdateStateThisFrame; public void Initialize() { foreach (var state in states) { //state.TransitionState = InternalTransitionState; state.Initialize(); StateDictionary.Add(state.GetType(), state); } if (states.Count > 0) { TransitionState(states[0]); } } public void UpdateState(float deltaTime) { if(transitionOnNextFrame && _nextState.TryGetRelease(out var nextState)) TransitionStateInternal(nextState); if (Enabled) { if (cancelUpdateStateThisFrame is false) { CurrentState?.OnStateUpdate(deltaTime); } cancelUpdateStateThisFrame = false; } } public void DisposeState() { } public void TransitionState() where State : TState { var nextState = StateDictionary.GetOrCreate(typeof(State)); TransitionState(nextState); } public void TransitionState(TState newState) { if(transitionOnNextFrame) _nextState.Release(newState); else { TransitionStateInternal(newState); cancelUpdateStateThisFrame = true; } } private void TransitionStateInternal(TState newState) { if (newState.Equals(CurrentState)) return; var oldState = CurrentState; if (oldState is not null) { oldState.OnStateExit(oldState, newState); oldState.Enabled = false; } if (debug) { BIT4Log.Log>($"TransitionState from {_currentStateName} to {newState.GetType().Name}"); } newState.OnStateEntry(oldState); CurrentState = newState; OnStateChanged?.Invoke(oldState, newState); _currentStateName = newState.GetType().Name; newState.Enabled = true; } } }