unity-atoms/Packages/FSM/Runtime/FiniteStateMachine/FiniteStateMachine.cs

143 lines
4.9 KiB
C#
Raw Normal View History

2020-03-08 07:32:41 -04:00
using System.Collections.Generic;
using UnityEngine;
using UnityAtoms.BaseAtoms;
namespace UnityAtoms.FSM
{
2020-03-08 15:41:22 -04:00
[EditorIcon("atom-icon-delicate")]
[CreateAssetMenu(menuName = "Unity Atoms/FSM/Finite State Machine", fileName = "FiniteStateMachine")]
2020-03-08 07:32:41 -04:00
public class FiniteStateMachine : StringVariable
{
public override string Value { get => _value; set => Dispatch(value); }
2020-03-08 08:24:46 -04:00
public StringReference InitialState { get => _initialState; }
public FSMTransitionDataEvent TransitionStarted { get => _transitionStarted; set => _transitionStarted = value; }
public BoolEvent CompleteCurrentTransition { get => _completeCurrentTransition; set => _completeCurrentTransition = value; }
2020-03-08 15:41:22 -04:00
public override string InitialValue { get => _initialState.Value; }
2020-03-08 07:32:41 -04:00
/// <summary>
/// Gets a boolean value indicating if the state machine is currently transitioning.
/// </summary>
public bool IsTransitioning { get => _currentTransition != null; }
public bool IsAtEndState
{
get
{
for (var i = 0; i < _transitions.Count; ++i)
{
var transition = _transitions[i];
if (transition.FromState == Value)
{
return true;
}
}
return false;
}
}
[SerializeField]
private StringReference _initialState = default(StringReference);
[SerializeField]
2020-03-08 08:24:46 -04:00
private FSMTransitionDataEvent _transitionStarted = default(FSMTransitionDataEvent);
2020-03-08 07:32:41 -04:00
[SerializeField]
private BoolEvent _completeCurrentTransition = default(BoolEvent);
[SerializeField]
private List<Transition> _transitions;
private bool _isUpdatingState = false;
private Transition _currentTransition = null;
private bool _resetOnNextTransitionCompleted = false;
public void Begin()
{
2020-03-08 15:41:22 -04:00
_currentTransition = null;
2020-03-08 07:32:41 -04:00
if (!_resetOnNextTransitionCompleted && !IsTransitioning)
{
2020-03-08 15:41:22 -04:00
_resetOnNextTransitionCompleted = false;
2020-03-08 07:32:41 -04:00
base.Reset(false);
}
else
{
2020-03-08 15:41:22 -04:00
Debug.Log("Asdf");
2020-03-08 07:32:41 -04:00
_resetOnNextTransitionCompleted = true;
}
}
/// <summary>
/// Dispatches a new command to the FiniteStateMachine, invoking any necessary transitions.
/// </summary>
/// <param name="command"></param>
public void Dispatch(string command)
{
// Commands dispatched during transition will be ignored
if (IsTransitioning)
return;
var transition = FindTransitionForCurrentState(command);
if (transition != null)
{
// Commands should not be dispatched in events listening to state changes of this machine
if (_isUpdatingState)
{
Debug.LogWarning("Do not call Dispatch from handlers listening to Changed and ChangedWithHistory events.");
return;
}
if (transition.TestCondition())
{
_currentTransition = transition;
if (_transitionStarted != null)
{
_transitionStarted.Raise(
2020-03-08 08:24:46 -04:00
new FSMTransitionData()
2020-03-08 07:32:41 -04:00
{
FromState = transition.FromState,
ToState = transition.ToState,
Command = transition.Command,
CompleteTransition = _completeCurrentTransition,
}
);
}
transition.Begin(this);
}
}
}
public void EndCurrentTransition()
{
if (_resetOnNextTransitionCompleted)
{
2020-03-08 15:41:22 -04:00
_resetOnNextTransitionCompleted = false;
2020-03-08 07:32:41 -04:00
Begin();
return;
}
_isUpdatingState = true;
2020-03-08 15:41:22 -04:00
Debug.Log("Updating to " + _currentTransition.ToState);
2020-03-08 07:32:41 -04:00
base.Value = _currentTransition.ToState;
2020-03-08 15:41:22 -04:00
_currentTransition = null;
2020-03-08 07:32:41 -04:00
_isUpdatingState = false;
}
private Transition FindTransitionForCurrentState(string command)
{
Transition ret = null;
for (var i = 0; i < _transitions.Count; ++i)
{
var transition = _transitions[i];
2020-03-08 15:41:22 -04:00
// Debug.Log($"Command {command} - From State {transition.FromState}. Current State {Value}.");
2020-03-08 07:32:41 -04:00
if (command == transition.Command && Value == transition.FromState)
{
2020-03-08 15:41:22 -04:00
return transition;
2020-03-08 07:32:41 -04:00
}
}
return ret;
}
}
}