Last active
October 21, 2022 23:54
-
-
Save mandarinx/734ca9f02a8eccaa3c3e to your computer and use it in GitHub Desktop.
Unity3D Simple Finite 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 MyGame; | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace MyGame.FSM { | |
public abstract class FSMState { | |
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>(); | |
protected StateID stateID; | |
protected FSMSystem fsmSystem; | |
public FSMSystem FSMSystem { | |
set { this.fsmSystem = value; } | |
} | |
public StateID ID { | |
get { return stateID; } | |
} | |
public void AddTransition(Transition trans, StateID id) { | |
if (trans == Transition.NullTransition) { | |
Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition"); | |
return; | |
} | |
if (id == StateID.NullStateID) { | |
Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID"); | |
return; | |
} | |
if (map.ContainsKey(trans)) { | |
Debug.LogError("FSMState ERROR: State " + stateID.ToString() + | |
" already has transition " + trans.ToString() + | |
"Impossible to assign to another state"); | |
return; | |
} | |
map.Add(trans, id); | |
} | |
public void DeleteTransition(Transition trans) { | |
if (trans == Transition.NullTransition) { | |
Debug.LogError("FSMState ERROR: NullTransition is not allowed"); | |
return; | |
} | |
if (map.ContainsKey(trans)) { | |
map.Remove(trans); | |
return; | |
} | |
Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + | |
" passed to " + stateID.ToString() + | |
" was not on the state's transition list"); | |
} | |
public bool SetTransition(Transition trans, System.Object options = null) { | |
return fsmSystem.PerformTransition(trans, options); | |
} | |
public StateID GetOutputState(Transition trans) { | |
if (map.ContainsKey(trans)) { | |
return map[trans]; | |
} | |
return StateID.NullStateID; | |
} | |
public virtual void DoBeforeEntering(System.Object options) { } | |
public virtual void DoBeforeLeaving() { } | |
public virtual bool Reason() { | |
return true; | |
} | |
public abstract void Act(); | |
public override string ToString() { | |
return stateID.ToString(); | |
} | |
} | |
} |
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
namespace MyGame.FSM { | |
public enum Transition { | |
NullTransition = 0, | |
OneTwo = 10, | |
TwoOne = 20 | |
} | |
public enum StateID { | |
NullStateID = 0, | |
One = 10, | |
Two = 20 | |
} | |
} |
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 MyGame.FSM; | |
using UnityEngine; | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
namespace MyGame.FSM { | |
public class FSMSystem { | |
private List<FSMState> states; | |
private StateID currentStateID; | |
private FSMState currentState; | |
public StateID CurrentStateID { | |
get { return currentStateID; } | |
} | |
public FSMState CurrentState { | |
get { return currentState; } | |
} | |
public FSMSystem() { | |
states = new List<FSMState>(); | |
} | |
public void AddState(FSMState state) { | |
if (state == null) { | |
Debug.LogError("FSM ERROR: Null reference is not allowed"); | |
} | |
foreach (FSMState st in states) { | |
if (st.ID == state.ID) { | |
Debug.LogError("FSM ERROR: Impossible to add state " + | |
state.ID.ToString() + | |
" because state has already been added"); | |
return; | |
} | |
} | |
state.FSMSystem = this; | |
states.Add(state); | |
if (states.Count == 1) { | |
currentState = state; | |
currentStateID = state.ID; | |
} | |
} | |
public void DeleteState(StateID id) { | |
if (id == StateID.NullStateID) { | |
Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state"); | |
return; | |
} | |
foreach (FSMState state in states) { | |
if (state.ID == id) { | |
states.Remove(state); | |
return; | |
} | |
} | |
Debug.LogError("FSM ERROR: Impossible to delete state " + | |
id.ToString() + | |
". It was not on the list of states"); | |
} | |
public bool CanPerformTransition(Transition trans) { | |
StateID id = currentState.GetOutputState(trans); | |
if (id == StateID.NullStateID) { | |
return false; | |
} | |
return true; | |
} | |
public bool PerformTransition(Transition trans, System.Object options = null) { | |
if (!CanPerformTransition(trans)) { | |
return false; | |
} | |
if (trans == Transition.NullTransition) { | |
Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition"); | |
return false; | |
} | |
StateID id = currentState.GetOutputState(trans); | |
if (id == StateID.NullStateID) { | |
Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + | |
" does not have a target state " + | |
" for transition " + trans.ToString()); | |
return false; | |
} | |
foreach (FSMState state in states) { | |
if (state.ID == id) { | |
currentStateID = id; | |
currentState.DoBeforeLeaving(); | |
currentState = state; | |
currentState.DoBeforeEntering(options); | |
break; | |
} | |
} | |
return true; | |
} | |
public void Update() { | |
if (currentState.Reason()) { | |
currentState.Act(); | |
} | |
} | |
} | |
} |
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 UnityEngine; | |
namespace MyGame.FSM.States { | |
public class OneOptions : System.Object { | |
public float oneFloat; | |
} | |
public class TwoOptions : System.Object { | |
public bool twoBool; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's an example of how to use the files above:
And here are the states: