diff options
author | chai <chaifix@163.com> | 2022-06-28 09:40:37 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2022-06-28 09:40:37 +0800 |
commit | 49b25e755b70ec412feaaf0b898d6f7e09d2bea6 (patch) | |
tree | 3c5f4260f30d1c2d7196db93153700d7ddec3157 /Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs | |
parent | c92269331692feca2c276649f6c4ee8911f1f859 (diff) |
+node example
Diffstat (limited to 'Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs')
-rw-r--r-- | Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs b/Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs new file mode 100644 index 00000000..9c3a8992 --- /dev/null +++ b/Other/NodeEditorExamples/Assets/UNEB/Utility/StateMachine.cs @@ -0,0 +1,300 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace Bonsai.Utility +{ + /// <summary> + /// A finite state machine. + /// </summary> + /// <typeparam name="T">The date type to be stored by the machine states.</typeparam> + public class StateMachine<T> + { + /// <summary> + /// An event that fires when the machine finishes transitioning to another state. + /// </summary> + public event Action OnStateChangedEvent = delegate { }; + + protected Dictionary<T, State> _states = new Dictionary<T, State>(); + + /// <summary> + /// Get all the state data. + /// </summary> + /// <returns></returns> + public IEnumerable<T> Data() + { + return _states.Keys; + } + + protected State _currentState; + + public State CurrentState + { + get { return _currentState; } + } + + /// <summary> + /// Adds a state to the machine. + /// </summary> + /// <param name="data"></param> + public void AddState(T data) + { + var s = new State(data); + _states.Add(data, s); ; + } + + public void AddState(State s) + { + _states.Add(s.Value, s); + } + + public void AddTransition(State start, State end, Func<bool> condition, Func<bool> onMakingTransition) + { + var t = new Transition(condition); + t.onMakingTransition = onMakingTransition; + + AddTransition(start, end, t); + } + + public void AddTransition(State start, State end, Transition t) + { + start.Add(t); + t.SetNextState(end); + } + + /// <summary> + /// Add a transition that goes from start to end state. + /// </summary> + /// <param name="start"></param> + /// <param name="end"></param> + /// <param name="t"></param> + public void AddTransition(T start, T end, Transition t) + { + var startST = GetState(start); + var endST = GetState(end); + + if (startST == null || endST == null) { + Debug.LogError("State(s) are not in the state machine"); + return; + } + + AddTransition(startST, endST, t); + } + + /// <summary> + /// Add two transitions. + /// One from start to end. + /// Another from end to start. + /// </summary> + /// <param name="start"></param> + /// <param name="end"></param> + /// <param name="startToEnd"></param> + /// <param name="endToStart"></param> + public void AddBiTransition(T start, T end, Transition startToEnd, Transition endToStart) + { + var startST = GetState(start); + var endST = GetState(end); + + if (startST == null || endST == null) { + Debug.LogError("State(s) are not in the state machine"); + return; + } + + AddTransition(startST, endST, startToEnd); + AddTransition(endST, startST, endToStart); + } + + /// <summary> + /// Gets the state associated with the data. + /// </summary> + /// <param name="data"></param> + /// <returns></returns> + public State GetState(T data) + { + if (_states.ContainsKey(data)) { + return _states[data]; + } + + return null; + } + + /// <summary> + /// Sets the current active state of the machine. + /// </summary> + /// <param name="data"></param> + public void SetCurrentState(T data) + { + + var state = GetState(data); + + if (state == null) { + Debug.LogError(data + " is not in the state machine."); + } + + else { + _currentState = state; + } + } + + /// <summary> + /// Handles moving to next state when conditions are met. + /// </summary> + public void Update() + { + if (_currentState == null) { + return; + } + + Transition validTrans = null; + + // Pick the next state if the transition conditions are met. + for (int i = 0; i < _currentState.Transitions.Count; i++) { + + if (_currentState.Transitions[i].AllConditionsMet()) { + validTrans = _currentState.Transitions[i]; + break; + } + } + + if (validTrans != null) { + + // Call on making transition. + if (validTrans.onMakingTransition()) { + + // Call on state exit. + if (_currentState.onStateExit != null) + _currentState.onStateExit(); + + // Change the state to the next one. + _currentState = validTrans.NextState; + + // Call on state enter. + if (_currentState.onStateEnter != null) + _currentState.onStateEnter(); + + OnStateChangedEvent(); + } + } + } + + /// <summary> + /// A transition between two states than only occurs if all + /// its conditions are satisfied. + /// </summary> + public class Transition + { + private State _nextState = null; + private List<Func<bool>> _conditions = new List<Func<bool>>(); + + /// <summary> + /// Called after the 'from' state exits and before the 'to' state enters. + /// If this fails, then it goes back to the starting state. + /// </summary> + public Func<bool> onMakingTransition = () => { return true; }; + + public Transition() + { + + } + + /// <summary> + /// Pass in initial conditions + /// </summary> + /// <param name="?"></param> + public Transition(params Func<bool>[] conditions) + { + foreach (var c in conditions) { + AddCondition(c); + } + } + + /// <summary> + /// Adds a condition that must be satisfied in order to do the transition. + /// </summary> + /// <param name="cond"></param> + public void AddCondition(Func<bool> cond) + { + _conditions.Add(cond); + } + + /// <summary> + /// Tests if all the conditions of the transition are satisfied. + /// </summary> + /// <returns></returns> + public bool AllConditionsMet() + { + for (int i = 0; i < _conditions.Count; i++) { + + if (!_conditions[i]()) return false; + } + + // All conditions returned true. + return true; + } + + /// <summary> + /// Set the state that transition goes to. + /// </summary> + /// <param name="next"></param> + public void SetNextState(State next) + { + _nextState = next; + } + + /// <summary> + /// The state that transition goes to. + /// </summary> + public State NextState + { + get { return _nextState; } + } + } + + /// <summary> + /// A state of the machine. + /// </summary> + public class State + { + private T _data; + private List<Transition> _transitions = new List<Transition>(); + + /// <summary> + /// Executes when the machine transitions into this state. + /// </summary> + public Action onStateEnter; + + /// <summary> + /// Executes when the machine transitions out of this state. + /// </summary> + public Action onStateExit; + + /// <summary> + /// Construct a state with its data. + /// </summary> + /// <param name="data"></param> + public State(T data) + { + _data = data; + } + + /// <summary> + /// Adds a transition to the state. + /// </summary> + /// <param name="t"></param> + public void Add(Transition t) + { + _transitions.Add(t); + } + + /// <summary> + /// The data held by the state. + /// </summary> + public T Value { get { return _data; } } + + /// <summary> + /// The transitions connected to the state. + /// </summary> + public List<Transition> Transitions { get { return _transitions; } } + } + } +}
\ No newline at end of file |