I’m following along a tutorial about State Machines and trying to implement it. I have a simple setup now but it is not working. Well I can log from the HeroIdle, but when changing the move float, I do not switch to the HeroRun state. Can anyone help me why that is?
public interface IState
{
void Tick();
void OnEnter();
void OnExit();
}
public class StateMachine
{
private IState _currentState;
private Dictionary<Type, List<Transition>> _transition = new Dictionary<Type, List<Transition>>();
private List<Transition> _currentTransitions = new List<Transition>();
private List<Transition> _anyTransitions = new List<Transition>();
private static List<Transition> EmptyTransitions = new List<Transition>(0);
public void Tick()
{
var transition = GetTransition();
if (transition != null)
SetState(transition.To);
_currentState?.Tick();
}
public void SetState(IState state)
{
if (state == _currentState)
return;
_currentState?.OnExit();
_currentState = state;
_transition.TryGetValue(_currentState.GetType(), out _currentTransitions);
if (_currentTransitions == null)
{
_currentTransitions = EmptyTransitions;
}
_currentState.OnEnter();
}
public void AddTransition(IState from, IState to, Func<bool> predicate)
{
if (_transition.TryGetValue(from.GetType(), out var transitions) == false)
{
transitions = new List<Transition>();
_transition[from.GetType()] = transitions;
}
transitions.Add(new Transition(to, predicate));
}
public void AddAnyTransition(IState state, Func<bool> predicate)
{
_anyTransitions.Add(new Transition(state, predicate));
}
private class Transition
{
public Func<bool> Condition { get; }
public IState To { get; }
public Transition(IState to, Func<bool> condition)
{
To = to;
Condition = condition;
}
}
private Transition GetTransition()
{
foreach (var transition in _anyTransitions)
if (transition.Condition())
return transition;
foreach (var transition in _currentTransitions)
if (transition.Condition())
return transition;
return null;
}
}
public class Hero : MonoBehaviour
{
private StateMachine _stateMachine;
private float move = 0f;
private void Awake()
{
var animator = GetComponent<Animator>();
_stateMachine = new StateMachine();
var heroIdle = new HeroIdle(this, animator);
var heroRun = new HeroRun(this, animator);
_stateMachine.SetState(heroIdle);
At(heroIdle, heroRun, IsRunning());
At(heroRun, heroIdle, IsNotRunning());
void At(IState from, IState to, Func<bool> condition) => _stateMachine.AddTransition(from, to, condition);
Func<bool> IsRunning() => () => move != 0;
Func<bool> IsNotRunning() => () => move == 0;
}
void Update()
{
_stateMachine.Tick();
move = Input.GetAxisRaw("Horizontal");
}
}
public class HeroIdle : IState
{
private readonly Hero _hero;
private readonly Animator _animator;
public HeroIdle(Hero hero, Animator animator)
{
_hero = hero;
_animator = animator;
}
public void Tick()
{
Debug.Log("we are idle");
}
public void OnEnter()
{
}
public void OnExit()
{
throw new System.NotImplementedException();
}
}
public class HeroRun : IState
{
private readonly Hero _hero;
private readonly Animator _animator;
public HeroRun(Hero hero, Animator animator)
{
_hero = hero;
_animator = animator;
}
public void Tick()
{
Debug.Log("we are running");
}
public void OnEnter()
{
throw new System.NotImplementedException();
}
public void OnExit()
{
throw new System.NotImplementedException();
}
}