123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
- using UnityEngine;
- namespace Animancer.FSM
- {
- public partial class StateMachine<TState>
- {
- /// <summary>
- /// A simple system that can <see cref="InputBuffer{TStateMachine}.State"/> a state then try to enter it every time
- /// <see cref="InputBuffer{TStateMachine}.Update(float)"/> is called until the
- /// <see cref="InputBuffer{TStateMachine}.TimeOut"/> expires.
- /// </summary>
- ///
- /// <remarks>
- /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/fsm/utilities#input-buffers">Input Buffers</see>
- /// </remarks>
- ///
- /// <example>See <see cref="StateMachine{TState}.InputBuffer{TStateMachine}"/>.</example>
- ///
- /// https://kybernetik.com.au/animancer/api/Animancer.FSM/InputBuffer
- ///
- public class InputBuffer : InputBuffer<StateMachine<TState>>
- {
- /************************************************************************************************************************/
- /// <summary>Creates a new <see cref="InputBuffer"/>.</summary>
- public InputBuffer() { }
- /// <summary>Creates a new <see cref="InputBuffer"/> for the specified `stateMachine`.</summary>
- public InputBuffer(StateMachine<TState> stateMachine) : base(stateMachine) { }
- /************************************************************************************************************************/
- }
- /// <summary>
- /// A simple system that can <see cref="Buffer"/> a state then try to enter it every time
- /// <see cref="Update(float)"/> is called until the <see cref="TimeOut"/> expires.
- /// </summary>
- ///
- /// <remarks>
- /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/fsm/utilities#input-buffers">Input Buffers</see>
- /// </remarks>
- ///
- /// <example><code>
- /// 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();
- /// }
- /// </code></example>
- ///
- /// https://kybernetik.com.au/animancer/api/Animancer.FSM/InputBuffer_1
- ///
- public class InputBuffer<TStateMachine> where TStateMachine : StateMachine<TState>
- {
- /************************************************************************************************************************/
- private TStateMachine _StateMachine;
- /// <summary>The <see cref="StateMachine{TState}"/> this buffer is feeding input to.</summary>
- public TStateMachine StateMachine
- {
- get => _StateMachine;
- set
- {
- _StateMachine = value;
- Clear();
- }
- }
- /// <summary>The <typeparamref name="TState"/> this buffer is currently attempting to enter.</summary>
- public TState State { get; set; }
- /// <summary>The amount of time left before the <see cref="State"/> is cleared.</summary>
- public float TimeOut { get; set; }
- /************************************************************************************************************************/
- /// <summary>Is this buffer currently trying to enter a <see cref="State"/>?</summary>
- public bool IsActive => State != null;
- /************************************************************************************************************************/
- /// <summary>Creates a new <see cref="InputBuffer{TStateMachine}"/>.</summary>
- public InputBuffer() { }
- /// <summary>Creates a new <see cref="InputBuffer{TStateMachine}"/> for the specified `stateMachine`.</summary>
- public InputBuffer(TStateMachine stateMachine) => _StateMachine = stateMachine;
- /************************************************************************************************************************/
- /// <summary>Sets the <see cref="State"/> and <see cref="TimeOut"/>.</summary>
- /// <remarks>Doesn't actually attempt to enter the state until <see cref="Update(float)"/> is called.</remarks>
- public void Buffer(TState state, float timeOut)
- {
- State = state;
- TimeOut = timeOut;
- }
- /************************************************************************************************************************/
- /// <summary>Attempts to enter the <see cref="State"/> and returns true if successful.</summary>
- protected virtual bool TryEnterState() => StateMachine.TryResetState(State);
- /************************************************************************************************************************/
- /// <summary>Calls <see cref="Update(float)"/> using <see cref="Time.deltaTime"/>.</summary>
- /// <remarks>This method should be called at the end of a frame after any calls to <see cref="Buffer"/>.</remarks>
- public bool Update() => Update(Time.deltaTime);
- /// <summary>
- /// Attempts to enter the <see cref="State"/> if there is one and returns true if successful. Otherwise the
- /// <see cref="TimeOut"/> is decreased by `deltaTime` and <see cref="Clear"/> is called if it reaches 0.
- /// </summary>
- /// <remarks>This method should be called at the end of a frame after any calls to <see cref="Buffer"/>.</remarks>
- public bool Update(float deltaTime)
- {
- if (IsActive)
- {
- if (TryEnterState())
- {
- Clear();
- return true;
- }
- else
- {
- TimeOut -= deltaTime;
- if (TimeOut < 0)
- Clear();
- }
- }
- return false;
- }
- /************************************************************************************************************************/
- /// <summary>Clears this buffer so it stops trying to enter the <see cref="State"/>.</summary>
- public virtual void Clear()
- {
- State = null;
- TimeOut = default;
- }
- /************************************************************************************************************************/
- }
- }
- }
|