StateExtensions Class

Summary

Various extension methods for Animancer.FSM.IOwnedState`1.
Assembly
Animancer.dll
Namespace
Animancer.FSM
Base Types
  • Object
graph BT Type-->Base0["Object"] Type["StateExtensions"] class Type type-node

Syntax

[HelpURL(APIDocumentationURL + nameof(StateExtensions))]
public static class StateExtensions

Examples

public class Creature : MonoBehaviour
{
    public StateMachine<CreatureState> StateMachine { get; private set; }
}

public class CreatureState : StateBehaviour, IOwnedState<CreatureState>
{
    [SerializeField]
    private Creature _Creature;
    public Creature Creature => _Creature;
    
    public StateMachine<CreatureState> OwnerStateMachine => _Creature.StateMachine;
}

public class CreatureBrain : MonoBehaviour
{
    [SerializeField] private Creature _Creature;
    [SerializeField] private CreatureState _Jump;
    
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // Normally you would need to refer to both the state machine and the state:
            _Creature.StateMachine.TrySetState(_Jump);
            
            // But since CreatureState implements IOwnedState you can use these extension methods:
            _Jump.TryEnterState();
        }
    }
}

Inherited Types

Unfortunately, if the field type is not the same as the T in the IOwnedState<T> implementation then attempting to use these extension methods without specifying the generic argument will give the following error:

The type 'StateType' cannot be used as type parameter 'TState' in the generic type or method 'StateExtensions.TryEnterState<TState>(TState)'. There is no implicit reference conversion from 'StateType' to 'Animancer.FSM.IOwnedState<StateType>'.

For example, you might want to access members of a derived state class like this SetTarget method:

public class AttackState : CreatureState
{
    public void SetTarget(Transform target) { }
}

public class CreatureBrain : MonoBehaviour
{
    [SerializeField] private AttackState _Attack;
    
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            _Attack.SetTarget(...)
            // Can't do _Attack.TryEnterState();
            _Attack.TryEnterState<CreatureState>();
        }
    }
}
Unlike the _Jump example, the _Attack field is an AttackState rather than the base CreatureState so we can call _Attack.SetTarget(...) but that causes problems with these extension methods.

Calling the method without specifying its generic argument automatically uses the variable's type as the argument so both of the following calls do the same thing:

_Attack.TryEnterState();
_Attack.TryEnterState<AttackState>();

The problem is that AttackState inherits the implementation of IOwnedState from the base CreatureState class. But since that implementation is IOwnedState<CreatureState>, rather than IOwnedState<AttackState> that means TryEnterState<AttackState> does not satisfy that method's generic constraints: where TState : class, IOwnedState<TState>

That is why you simply need to specify the base class which implements IOwnedState as the generic argument to prevent it from inferring the wrong type:

_Attack.TryEnterState<CreatureState>();

Attributes

Type Description
HelpURLAttribute

Fields

Name Constant Value Summary
APIDocumentationURL https://kybernetik.com.au/animancer/api/Animancer.FSM/
The URL of the API documentation for the Animancer.FSM system.
static

Methods

Name Value Summary
CanEnterState<TState>(TState) bool
Checks if it is currently possible to enter the specified `state`. This requires Animancer.FSM.IState`1.CanExitState(`0) on the Animancer.FSM.StateMachine`1.CurrentState and Animancer.FSM.IState`1.CanEnterState(`0) on the specified `state` to both return true.
static
ForceEnterState<TState>(TState) void
Calls Animancer.FSM.IState`1.OnExitState on the Animancer.FSM.StateMachine`1.CurrentState then changes to the specified `state` and calls Animancer.FSM.IState`1.OnEnterState on it.

This method does not check Animancer.FSM.IState`1.CanExitState(`0) or Animancer.FSM.IState`1.CanEnterState(`0). To do that, you should use TrySetState instead.
static
IsCurrentState<TState>(TState) bool
Checks if the specified `state` is the Animancer.FSM.StateMachine`1.CurrentState in its Animancer.FSM.IOwnedState`1.OwnerStateMachine.
static
TryEnterState<TState>(TState) bool
Attempts to enter the specified `state` and returns true if successful.

This method returns true immediately if the specified `state` is already the Animancer.FSM.StateMachine`1.CurrentState. To allow directly re-entering the same state, use Animancer.FSM.StateExtensions.TryReEnterState``1(``0) instead.
static
TryReEnterState<TState>(TState) bool
Attempts to enter the specified `state` and returns true if successful.

This method does not check if the `state` is already the Animancer.FSM.StateMachine`1.CurrentState. To do so, use Animancer.FSM.StateExtensions.TryEnterState``1(``0) instead.
static