You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
9.4 KiB
C#
194 lines
9.4 KiB
C#
3 months ago
|
// Animancer // Copyright 2020 Kybernetik //
|
||
|
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace Animancer.FSM
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// A state that can be used in a <see cref="StateMachine{TState}"/>.
|
||
|
/// </summary>
|
||
|
public interface IState<TState> where TState : class, IState<TState>
|
||
|
{
|
||
|
/// <summary>Determines whether this state can be entered.</summary>
|
||
|
bool CanEnterState(TState previousState);
|
||
|
|
||
|
/// <summary>Determines whether this state can be exited.</summary>
|
||
|
bool CanExitState(TState nextState);
|
||
|
|
||
|
/// <summary>Called when this state is entered.</summary>
|
||
|
void OnEnterState();
|
||
|
|
||
|
/// <summary>Called when this state is exited.</summary>
|
||
|
void OnExitState();
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// A type of <see cref="IState{TState}"/> that knows which <see cref="StateMachine{TState}"/> it is used in so it
|
||
|
/// can be used with various extension methods in <see cref="StateExtensions"/>.
|
||
|
/// </summary>
|
||
|
public interface IOwnedState<TState> : IState<TState> where TState : class, IState<TState>
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// The <see cref="StateMachine{TState}"/> that this state is used in.
|
||
|
/// </summary>
|
||
|
StateMachine<TState> OwnerStateMachine { get; }
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Various extension methods for <see cref="IOwnedState{TState}"/>.
|
||
|
/// </summary>
|
||
|
[HelpURL(APIDocumentationURL + "StateExtensions")]
|
||
|
public static class StateExtensions
|
||
|
{
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>The URL of the website where the Animancer API documentation is hosted.</summary>
|
||
|
/// <remarks>
|
||
|
/// This is a duplicate of <c>Strings.APIDocumentationURL</c> so that the <see cref="FSM"/> system does not
|
||
|
/// have any dependencies on <see cref="Animancer"/> itself.
|
||
|
/// </remarks>
|
||
|
public const string APIDocumentationURL = "https://kybernetik.com.au/animancer/api/Animancer.FSM/";
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the specified `state` is the <see cref="StateMachine{TState}.CurrentState"/> in its
|
||
|
/// <see cref="IOwnedState{TState}.OwnerStateMachine"/>.
|
||
|
/// </summary>
|
||
|
public static bool IsCurrentState<TState>(this TState state) where TState : class, IOwnedState<TState>
|
||
|
{
|
||
|
return state.OwnerStateMachine.CurrentState == state;
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if it is currently possible to enter the specified `state`. This requires
|
||
|
/// <see cref="IState{TState}.CanExitState"/> on the <see cref="StateMachine{TState}.CurrentState"/> and
|
||
|
/// <see cref="IState{TState}.CanEnterState"/> on the specified `state` to both return true.
|
||
|
/// </summary>
|
||
|
public static bool CanEnterState<TState>(this TState state) where TState : class, IOwnedState<TState>
|
||
|
{
|
||
|
return state.OwnerStateMachine.CanSetState(state);
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Attempts to enter the specified `state` and returns true if successful.
|
||
|
/// <para></para>
|
||
|
/// This method returns true immediately if the specified `state` is already the
|
||
|
/// <see cref="StateMachine{TState}.CurrentState"/>. To allow directly re-entering the same state, use
|
||
|
/// <see cref="TryReEnterState"/> instead.
|
||
|
/// </summary>
|
||
|
public static bool TryEnterState<TState>(this TState state) where TState : class, IOwnedState<TState>
|
||
|
{
|
||
|
return state.OwnerStateMachine.TrySetState(state);
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Attempts to enter the specified `state` and returns true if successful.
|
||
|
/// <para></para>
|
||
|
/// This method does not check if the `state` is already the <see cref="StateMachine{TState}.CurrentState"/>.
|
||
|
/// To do so, use <see cref="TryEnterState"/> instead.
|
||
|
/// </summary>
|
||
|
public static bool TryReEnterState<TState>(this TState state) where TState : class, IOwnedState<TState>
|
||
|
{
|
||
|
return state.OwnerStateMachine.TryResetState(state);
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
|
||
|
/// <summary>
|
||
|
/// Calls <see cref="IState{TState}.OnExitState"/> on the <see cref="StateMachine{TState}.CurrentState"/> then
|
||
|
/// changes to the specified `state` and calls <see cref="IState{TState}.OnEnterState"/> on it.
|
||
|
/// <para></para>
|
||
|
/// This method does not check <see cref="IState{TState}.CanExitState"/> or
|
||
|
/// <see cref="IState{TState}.CanEnterState"/>. To do that, you should use <see cref="TrySetState"/> instead.
|
||
|
/// </summary>
|
||
|
public static void ForceEnterState<TState>(this TState state) where TState : class, IOwnedState<TState>
|
||
|
{
|
||
|
state.OwnerStateMachine.ForceSetState(state);
|
||
|
}
|
||
|
|
||
|
/************************************************************************************************************************/
|
||
|
#pragma warning disable CS1587 // XML comment is not placed on a valid language element.
|
||
|
// Copy this #region into a class which implements IOwnedState to give it the state extension methods as regular members.
|
||
|
///************************************************************************************************************************/
|
||
|
//#region State Extensions
|
||
|
///************************************************************************************************************************/
|
||
|
|
||
|
///// <summary>
|
||
|
///// Checks if this state is the <see cref="StateMachine{TState}.CurrentState"/> in its
|
||
|
///// <see cref="IOwnedState{TState}.OwnerStateMachine"/>.
|
||
|
///// </summary>
|
||
|
//public bool IsCurrentState()
|
||
|
//{
|
||
|
// return OwnerStateMachine.CurrentState == this;
|
||
|
//}
|
||
|
|
||
|
///************************************************************************************************************************/
|
||
|
|
||
|
///// <summary>
|
||
|
///// Checks if it is currently possible to enter this state. This requires
|
||
|
///// <see cref="IState{TState}.CanExitState"/> on the <see cref="StateMachine{TState}.CurrentState"/> and
|
||
|
///// <see cref="IState{TState}.CanEnterState"/> on this state to both return true.
|
||
|
///// </summary>
|
||
|
//public bool CanEnterState()
|
||
|
//{
|
||
|
// return OwnerStateMachine.CanSetState(this);
|
||
|
//}
|
||
|
|
||
|
///************************************************************************************************************************/
|
||
|
|
||
|
///// <summary>
|
||
|
///// Attempts to enter this state and returns true if successful.
|
||
|
///// <para></para>
|
||
|
///// This method returns true immediately if this state is already the
|
||
|
///// <see cref="StateMachine{TState}.CurrentState"/>. To allow directly re-entering the same state, use
|
||
|
///// <see cref="TryReEnterState"/> instead.
|
||
|
///// </summary>
|
||
|
//public bool TryEnterState()
|
||
|
//{
|
||
|
// return OwnerStateMachine.TrySetState(this);
|
||
|
//}
|
||
|
|
||
|
///************************************************************************************************************************/
|
||
|
|
||
|
///// <summary>
|
||
|
///// Attempts to enter this state and returns true if successful.
|
||
|
///// <para></para>
|
||
|
///// This method does not check if this state is already the <see cref="StateMachine{TState}.CurrentState"/>.
|
||
|
///// To do so, use <see cref="TryEnterState"/> instead.
|
||
|
///// </summary>
|
||
|
//public bool TryReEnterState()
|
||
|
//{
|
||
|
// return OwnerStateMachine.TryResetState(this);
|
||
|
//}
|
||
|
|
||
|
///************************************************************************************************************************/
|
||
|
|
||
|
///// <summary>
|
||
|
///// Calls <see cref="IState{TState}.OnExitState"/> on the <see cref="StateMachine{TState}.CurrentState"/> then
|
||
|
///// changes to the this state and calls <see cref="IState{TState}.OnEnterState"/> on it.
|
||
|
///// <para></para>
|
||
|
///// This method does not check <see cref="IState{TState}.CanExitState"/> or
|
||
|
///// <see cref="IState{TState}.CanEnterState"/>. To do that, you should use <see cref="TrySetState"/> instead.
|
||
|
///// </summary>
|
||
|
//public void ForceEnterState()
|
||
|
//{
|
||
|
// OwnerStateMachine.ForceSetState(this);
|
||
|
//}
|
||
|
|
||
|
///************************************************************************************************************************/
|
||
|
//#endregion
|
||
|
///************************************************************************************************************************/
|
||
|
}
|
||
|
}
|