You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.5 KiB
134 lines
4.5 KiB
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using ZelleGames.Log;
|
|
|
|
namespace ZelleGames.StateMachine
|
|
{
|
|
/// <summary>
|
|
/// Generic abstract state machine with OnEnter and OnExit features
|
|
/// </summary>
|
|
public abstract class StateMachine : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// Readonly State currently executing
|
|
/// </summary>
|
|
public State CurrentState { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Drive the current state if present
|
|
/// </summary>
|
|
private void Update()
|
|
{
|
|
if (CurrentState != null)
|
|
{
|
|
CurrentState.Update(Time.deltaTime);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Drive the current state's FixedUpdate method if state is present
|
|
/// </summary>
|
|
private void FixedUpdate()
|
|
{
|
|
if (CurrentState != null)
|
|
{
|
|
CurrentState.FixedUpdate(Time.fixedDeltaTime);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Public facing function to change state based on a transition.
|
|
/// Relies on an implementation of <see cref="GetNewState(Transition)"/>
|
|
/// </summary>
|
|
/// <param name="t">The transition to pass in. Validitiy depends on the implementation of GetNewState</param>
|
|
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}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load a new state without consideration of the GetNewState function.
|
|
/// This is sessentially the "goto" of state machine management, use only if absolutely needed.
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
public void ForceState(State s)
|
|
{
|
|
CurrentState.OnExit();
|
|
CurrentState = s;
|
|
CurrentState.OnEnter();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Derived classes should provide an implementation that returns a new <see cref="State"/> depending
|
|
/// on the Transition passed in.
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <returns>The new state for a valid transition for the current state,
|
|
/// Null otherwise to maintain current state</returns>
|
|
protected abstract State GetNewState(Transition t);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transitions are passed into the state machine to move from one state to the next.
|
|
/// </summary>
|
|
public abstract class Transition
|
|
{
|
|
/// <summary>
|
|
/// Generic object that can contain any information this transition needs to pass into the next state
|
|
/// </summary>
|
|
public object Context { get; }
|
|
|
|
public Transition() : this(null){}
|
|
|
|
public Transition(object ctx)
|
|
{
|
|
Context = ctx;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes a finite state for a <see cref="StateMachine"/>
|
|
/// in Unity.
|
|
/// </summary>
|
|
public abstract class State
|
|
{
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public StateMachine StateMachine;
|
|
|
|
/// <summary>
|
|
/// Called every frame by the <see cref="StateMachine"/>
|
|
/// </summary>
|
|
/// <param name="deltaTime"></param>
|
|
public abstract void Update(float deltaTime);
|
|
|
|
/// <summary>
|
|
/// Called according to the Physics timing configuration by the <see cref="StateMachine"/>
|
|
/// </summary>
|
|
/// <param name="fixedDeltaTime"></param>
|
|
public virtual void FixedUpdate(float fixedDeltaTime) { }
|
|
|
|
/// <summary>
|
|
/// Called on the frame the machine switches to this state
|
|
/// </summary>
|
|
public virtual void OnEnter() { }
|
|
|
|
/// <summary>
|
|
/// Called on the last frame before this state is replaced.
|
|
/// </summary>
|
|
public virtual void OnExit() { }
|
|
}
|
|
} |