// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2023 Kybernetik // using UnityEngine; namespace Animancer.FSM { public partial class StateMachine { /// /// A simple system that can a state then try to enter it every time /// is called until the /// expires. /// /// /// /// Documentation: Input Buffers /// /// /// See . /// /// https://kybernetik.com.au/animancer/api/Animancer.FSM/InputBuffer /// public class InputBuffer : InputBuffer> { /************************************************************************************************************************/ /// Creates a new . public InputBuffer() { } /// Creates a new for the specified `stateMachine`. public InputBuffer(StateMachine stateMachine) : base(stateMachine) { } /************************************************************************************************************************/ } /// /// A simple system that can a state then try to enter it every time /// is called until the expires. /// /// /// /// Documentation: Input Buffers /// /// /// /// public StateMachine<CharacterState> stateMachine;// Initialized elsewhere. /// /// [SerializeField] private CharacterState _Attack; /// [SerializeField] private float _AttackInputTimeOut = 0.5f; /// /// private StateMachine<CharacterState>.InputBuffer _InputBuffer; /// /// private void Awake() /// { /// // Initialize the buffer. /// _InputBuffer = new StateMachine<CharacterState>.InputBuffer(stateMachine); /// } /// /// private void Update() /// { /// // When input is detected, buffer the desired state. /// if (Input.GetButtonDown("Fire1"))// Left Click by default. /// { /// _InputBuffer.Buffer(_Attack, _AttackInputTimeOut); /// } /// /// // At the end of the frame, Update the buffer so it tries to enter the buffered state. /// // After the time out, it will clear itself so Update does nothing until something else is buffered. /// _InputBuffer.Update(); /// } /// /// /// https://kybernetik.com.au/animancer/api/Animancer.FSM/InputBuffer_1 /// public class InputBuffer where TStateMachine : StateMachine { /************************************************************************************************************************/ private TStateMachine _StateMachine; /// The this buffer is feeding input to. public TStateMachine StateMachine { get => _StateMachine; set { _StateMachine = value; Clear(); } } /// The this buffer is currently attempting to enter. public TState State { get; set; } /// The amount of time left before the is cleared. public float TimeOut { get; set; } /************************************************************************************************************************/ /// Is this buffer currently trying to enter a ? public bool IsActive => State != null; /************************************************************************************************************************/ /// Creates a new . public InputBuffer() { } /// Creates a new for the specified `stateMachine`. public InputBuffer(TStateMachine stateMachine) => _StateMachine = stateMachine; /************************************************************************************************************************/ /// Sets the and . /// Doesn't actually attempt to enter the state until is called. public void Buffer(TState state, float timeOut) { State = state; TimeOut = timeOut; } /************************************************************************************************************************/ /// Attempts to enter the and returns true if successful. protected virtual bool TryEnterState() => StateMachine.TryResetState(State); /************************************************************************************************************************/ /// Calls using . /// This method should be called at the end of a frame after any calls to . public bool Update() => Update(Time.deltaTime); /// /// Attempts to enter the if there is one and returns true if successful. Otherwise the /// is decreased by `deltaTime` and is called if it reaches 0. /// /// This method should be called at the end of a frame after any calls to . public bool Update(float deltaTime) { if (IsActive) { if (TryEnterState()) { Clear(); return true; } else { TimeOut -= deltaTime; if (TimeOut < 0) Clear(); } } return false; } /************************************************************************************************************************/ /// Clears this buffer so it stops trying to enter the . public virtual void Clear() { State = null; TimeOut = default; } /************************************************************************************************************************/ } } }