States don't need a reference to the StateMachine
they're used in for the system to function, however you can optionally implement IOwnedState
(which inherits from IState
) in order to use the Extension Methods in the StateExtensions
class with your states.
Example
The State Type implements IOwnedState
:
public abstract class CharacterState : StateBehaviour, IOwnedState<CharacterState>
{
[SerializeField]
private Character _Character;
public Character Character => _Character;
// Implement the OwnerStateMachine property from IOwnedState<CharacterState>:
public StateMachine<CharacterState> OwnerStateMachine => _Character.StateMachine;
// Make a non-generic state machine class for this state type:
[Serializable] public class StateMachine : StateMachine<CharacterState> { }
}
The class holding the StateMachine
looks the same as usual:
public class Character : MonoBehaviour
{
[SerializeField] private CharacterState.StateMachine _StateMachine;
public CharacterState.StateMachine StateMachine => _StateMachine;
protected virtual void Awake()
{
_StateMachine.InitializeAfterDeserialize();
}
}
And now other scripts that control the StateMachine
can be a bit simpler:
public class CharacterBrain : MonoBehaviour
{
[SerializeField] private Character _Character;
[SerializeField] private CharacterState _Walk;
protected virtual void Update()
{
if (Input.GetKey(KeyCode.W))
{
// Normally we would need to tell the StateMachine which state to enter.
_Character.StateMachine.TrySetState(_Walk);
// But since CharacterState implements IOwnedState we can do the same thing with:
_Walk.TryEnterState();
}
}
private bool IsWalking()
{
// Without IOwnedState:
return _Character.StateMachine.CurrentState == _Walk;
// With IOwnedState:
return _Walk.IsCurrentState();
}
}