Last active
January 21, 2023 06:51
-
-
Save takumifukasawa/3ee9ba66eba90b5b3a188a5f0b717904 to your computer and use it in GitHub Desktop.
unity simple state machine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEngine; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace Utilities | |
{ | |
public class StateMachine<T> where T : IConvertible | |
{ | |
public interface IState | |
{ | |
void Enter(); | |
void Update(); | |
void FixedUpdate(); | |
} | |
public class State : IState | |
{ | |
private T _state; | |
public System.Action OnEnter; | |
public System.Action OnLeave; | |
public System.Action OnUpdate; | |
public System.Action OnFixedUpdate; | |
public State(T state) | |
{ | |
_state = state; | |
} | |
public void Enter() | |
{ | |
OnEnter?.Invoke(); | |
} | |
public void Leave() | |
{ | |
OnLeave?.Invoke(); | |
} | |
public void Update() | |
{ | |
OnUpdate?.Invoke(); | |
} | |
public void FixedUpdate() | |
{ | |
OnFixedUpdate?.Invoke(); | |
} | |
} | |
private Dictionary<T, State> _states = new Dictionary<T, State>(); | |
private T _currentState = default(T); | |
private T _willNextState = default(T); | |
public System.Action<T, T> OnBeforeChangeState; | |
public System.Action OnAfterChangeState; | |
public System.Action<T, T> OnSwitchedState; | |
public T WillNextState | |
{ | |
get { return _willNextState; } | |
} | |
public T CurrentState | |
{ | |
get { return _currentState; } | |
} | |
public StateMachine(T initialState) | |
{ | |
var stateNames = System.Enum.GetValues(typeof(T)).Cast<T>().ToList(); | |
stateNames.ForEach(state => | |
{ | |
CreateState(state); | |
}); | |
// set initial state | |
_currentState = initialState; | |
} | |
public State CreateState(T s) | |
{ | |
State state = new State(s); | |
_states.Add(s, state); | |
return state; | |
} | |
public State GetState(T s) | |
{ | |
State state; | |
if (_states.TryGetValue(s, out state)) | |
{ | |
return state; | |
} | |
// TODO: throw error | |
Debug.LogError("invalid state"); | |
return null; | |
} | |
/// <summary> | |
/// stateを切り替えるときは必ずここを通す | |
/// </summary> | |
/// <param name="s"></param> | |
/// <param name="isImmediately"></param> | |
public void ChangeState(T s, bool isImmediately = false) | |
{ | |
_willNextState = s; | |
if (isImmediately) | |
{ | |
SwitchState(); | |
} | |
} | |
void SwitchState() | |
{ | |
T beforeState = _currentState; | |
if (OnBeforeChangeState != null) | |
{ | |
OnBeforeChangeState.Invoke(_currentState, _willNextState); | |
} | |
_states[_currentState].Leave(); | |
_currentState = _willNextState; | |
_willNextState = default(T); | |
if (OnSwitchedState != null) | |
{ | |
OnSwitchedState.Invoke(beforeState, _currentState); | |
} | |
_states[_currentState].Enter(); | |
if (OnAfterChangeState != null) | |
{ | |
OnAfterChangeState.Invoke(); | |
} | |
} | |
public void Update() | |
{ | |
_states[_currentState].Update(); | |
} | |
void SwitchStateIfNeeded() | |
{ | |
if (!EqualityComparer<T>.Default.Equals(_willNextState, default(T))) | |
{ | |
SwitchState(); | |
} | |
} | |
public void Step() | |
{ | |
// NOTE: fixed update で呼んで大丈夫? | |
SwitchStateIfNeeded(); | |
} | |
public void FixedUpdate() | |
{ | |
_states[_currentState].FixedUpdate(); | |
} | |
public bool EqualsCurrentState(T s) | |
{ | |
return EqualityComparer<T>.Default.Equals(_currentState, s); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment