using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ZelleGames.Log;
namespace ZelleGames.StateMachine
{
///
/// Generic abstract state machine with OnEnter and OnExit features
///
public abstract class StateMachine : MonoBehaviour
{
///
/// Readonly State currently executing
///
public State CurrentState { get; protected set; }
///
/// Drive the current state if present
///
private void Update()
{
if (CurrentState != null)
{
CurrentState.Update(Time.deltaTime);
}
}
///
/// Drive the current state's FixedUpdate method if state is present
///
private void FixedUpdate()
{
if (CurrentState != null)
{
CurrentState.FixedUpdate(Time.fixedDeltaTime);
}
}
///
/// Public facing function to change state based on a transition.
/// Relies on an implementation of
///
/// The transition to pass in. Validitiy depends on the implementation of GetNewState
public void TransitionState(Transition t)
{
var newState = GetNewState(t);
if (newState != null)
{
CurrentState?.OnExit();
CurrentState = newState;
CurrentState.StateMachine = this;
CurrentState.OnEnter();
} else
{
Logging.Log(LogLevel.WARN, $"Could not transition from {CurrentState} with {t}");
}
}
///
/// Load a new state without consideration of the GetNewState function.
/// This is sessentially the "goto" of state machine management, use only if absolutely needed.
///
///
public void ForceState(State s)
{
CurrentState.OnExit();
CurrentState = s;
CurrentState.OnEnter();
}
///
/// Derived classes should provide an implementation that returns a new depending
/// on the Transition passed in.
///
///
/// The new state for a valid transition for the current state,
/// Null otherwise to maintain current state
protected abstract State GetNewState(Transition t);
}
///
/// Transitions are passed into the state machine to move from one state to the next.
///
public abstract class Transition
{
///
/// Generic object that can contain any information this transition needs to pass into the next state
///
public object Context { get; }
public Transition() : this(null){}
public Transition(object ctx)
{
Context = ctx;
}
}
///
/// Describes a finite state for a
/// in Unity.
///
public abstract class State
{
///
/// Reference to the parent statemachine. Derived classes can cast this reference into their specialized
/// class for specific statemachine functionality, or use this reference as is to operate on the base class
///
public StateMachine StateMachine;
///
/// Called every frame by the
///
///
public abstract void Update(float deltaTime);
///
/// Called according to the Physics timing configuration by the
///
///
public virtual void FixedUpdate(float fixedDeltaTime) { }
///
/// Called on the frame the machine switches to this state
///
public virtual void OnEnter() { }
///
/// Called on the last frame before this state is replaced.
///
public virtual void OnExit() { }
}
}