// 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;
}
/************************************************************************************************************************/
}
}