Reputation: 3
using System;
using System.Reflection;
using UnityEngine;
public class StateMachine<TStates> where TStates : Enum
{
private TStates initialState;
private TStates currentState;
private MonoBehaviour component;
public StateMachine(MonoBehaviour component)
{
this.component = component;
}
public StateMachine(MonoBehaviour component, TStates initialState)
{
this.component = component;
this.initialState = initialState;
SetState(this.initialState);
}
public void SetState(TStates newState)
{
Type componentType = component.GetType();
if (currentState != null)
{
if (currentState.Equals(newState))
return;
componentType.GetMethod("On" + currentState + "Exit", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(component, null);
}
else
initialState = newState;
currentState = newState;
componentType.GetMethod("On" + currentState + "Enter", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(component, null);
}
public void Update()
{
Type componentType = component.GetType();
if (currentState != null)
componentType.GetMethod("On" + currentState + "Update", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(component, null);
}
public void Reset()
{
if (initialState != null)
SetState(initialState);
}
}
I have a finite state machine that I tried making myself and it works fine. However, people told me that it isn't type safe.
They told me to use switch statements but I don't see how I'm able to implement them.
Any way I can make it type safe?
Upvotes: 0
Views: 79
Reputation: 1
You can easily make the state machine type-safe by introducing a common base class or an interface, which your states should inherit from. Given that, implementing the state machine design pattern is pretty straightforward:
public interface IState
{
void Handle(Context context);
}
public class Walk : IState
{
public void Handle(Context context)
{
context.State = new Shoot();
}
}
public class Shoot : IState
{
public void Handle(Context context)
{
context.State = new Walk();
}
}
public class Context
{
public Context(IState state)
{
this.State = state;
}
public IState State { get; set; }
public void Request()
{
this.State.Handle(this);
}
}
Upvotes: 0
Reputation: 2417
public interface IStateHandle<TStates> where TStates : Enum
{
void OnEnter(TStates state);
void OnUpdate(TStates state);
void OnExit(TStates state);
}
public class StateMachine<TStates> where TStates : Enum
{
IStateHandle<TStates> _handle;
TStates _currentState;
public StateMachine(IStateHandle<TStates> handle)
{
_handle = handle;
}
public void Update()
{
_handle.OnUpdate(_currentState);
}
}
Upvotes: 1
Reputation: 36361
You could for example replace your state with a state type that just uses methods, something like:
public interface IState{
void Exit();
void Enter();
void Update();
}
And provide an implementation for each state you want. You could also have a implementation that delegates the implementation of each method to a delegate.
Upvotes: 0