using System;
namespace OM
{
///
/// Interface for a state in a state machine.
///
///
public interface IOMState
{
///
/// called when the state is about to be entered from another state to check if the state can be entered.
///
///
///
bool CanEnterState(T fromState) => true;
///
/// called when the state is entered from another state.
///
///
void OnEnterState(T fromState);
///
/// called when the state is about to be exited to check if the state can be exited.
///
///
///
bool CanExitState(T toState) => true;
///
/// called when the state is exited to another state.
///
///
void OnExitState(T toState);
///
/// called every frame to update the state if the state is active.
///
void OnUpdateState() { }
}
///
/// A state machine that can be used to manage states in a generic way.
///
///
public class OMStateMachine where T : IOMState
{
///
/// event that is called when the state is changed.
///
public event Action OnStateChanged;
///
/// Last state before the current state.
///
public T LastState { get; private set; }
///
/// Current state of the state machine.
///
public T CurrentState { get; private set; }
///
/// Constructor for the state machine.
///
///
///
public OMStateMachine(T initState,Action onStateChanged = null)
{
SetNewState(initState);
if(onStateChanged != null) OnStateChanged += onStateChanged;
}
///
/// Sets a new state for the state machine and invokes the state changed event if the state has changed.
///
///
///
///
public bool SetNewState(T newState,bool force = false)
{
if(newState == null) return false;
if (!force)
{
if (!newState.CanEnterState(fromState:CurrentState)) return false;
if (CurrentState != null && !CurrentState.CanExitState(toState:newState)) return false;
}
CurrentState?.OnExitState(toState:newState);
LastState = CurrentState;
CurrentState = newState;
CurrentState?.OnEnterState(fromState:LastState);
OnStateChanged?.Invoke(CurrentState,LastState);
return true;
}
///
/// Updates the current state by calling the OnUpdateState method of the current state.
///
public void UpdateStateMachine()
{
CurrentState?.OnUpdateState();
}
///
/// Subscribes to the state changed event.
///
///
public void OnChange(Action callback)
{
OnStateChanged += callback;
}
}
}