using System.Collections.Generic; using System.Text; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; namespace XFFSM { /// /// RuntimeFSMController 运行时的示例 /// public class RuntimeFSMControllerInstance { public string name; public RuntimeFSMController RuntimeFSMController; // 所有的参数 internal Dictionary parameters = new Dictionary(); [Tooltip("参数的默认值")] internal Dictionary parameter_default = new Dictionary(); // 所有的状态 internal Dictionary states = new Dictionary(); internal List transitions = new List(); // 默认状态 internal FSMStateNode defaultState { get; private set; } = null; private Dictionary current_states = new Dictionary(); private List current_states_array = new List(); // 当前的过渡 public FSMTransition currentTransition { get; private set; } = null; public FSMController FSMController { get; private set; } /// /// 状态切换计数(为了避免状态切换进入死循环) /// private Dictionary state_count = new Dictionary(); /// /// 当前的帧数 /// private int currentSeconds = -1; /// /// 记录Trigger触发的次数 /// private Dictionary trigger_count = new Dictionary(); private List trigerKeys = new List(); public bool Started { get; private set; } = false; public RuntimeFSMControllerInstance(RuntimeFSMController runtimeFSMController, FSMController controller) { FSMController = controller; // 把数据复制一份 if (runtimeFSMController == null) return; name = runtimeFSMController.name; // 默认不执行任何状态 current_states.Clear(); RuntimeFSMController = GameObject.Instantiate(runtimeFSMController); #if UNITY_EDITOR RuntimeFSMController.originGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(runtimeFSMController)); #endif RuntimeFSMController.name = runtimeFSMController.name; // 参数 parameters.Clear(); for (int i = 0; i < RuntimeFSMController.parameters.Count; i++) { FSMParameterData data = RuntimeFSMController.parameters[i]; if (parameters.ContainsKey(data.name)) continue; data.onValueChange = null; parameters.Add(data.name, data); parameter_default.Add(data.name, data.Value); } // 状态 states.Clear(); for (int i = 0; i < RuntimeFSMController.states.Count; i++) { FSMStateNodeData stateData = RuntimeFSMController.states[i]; FSMStateNode state = new FSMStateNode(stateData, this); if (states.ContainsKey(stateData.name)) continue; if (stateData.defaultState && stateData.BaseLayer()) { defaultState = state; } states.Add(stateData.name, state); } // 过渡 transitions.Clear(); foreach (var item in runtimeFSMController.transitions) { FSMTransition transition = new FSMTransition(this, item); transitions.Add(transition); } Started = false; } // 启动 public void StartUp() { Started = true; // 找到默认状态 切换 SwitchState(defaultState, null); } public void Close() { // 切换到空状态 (当切换到空状态之后 就没有办法通过参数来切换状态) // 因为在判断条件是否满足时 会查询当前状态 如果当前状态为空 会直接return false; SwitchState(null, null); // 设置为非启动状态 Started = false; // 重置参数 ResetParamter(); } internal void SwitchState(FSMStateNode state, FSMTransition transition) { //if (!Started) return; int second = Mathf.FloorToInt(Time.time); if (second != currentSeconds) { currentSeconds = second; state_count.Clear(); // 清空状态 } // 添加状态 if (state != null) AddStateCount(state.data.name); string parent = state != null ? state.data.Parent : string.Empty; // 退出当前状态 ExitState(parent, state); EnterState(state); currentTransition = transition; // 检测当前状态是否有已经满足的条件 CheckConditionAndSwitch(); } private void CheckConditionAndSwitch() { // 检测当前的状态是否有已经满足条件的过渡 foreach (var item in transitions) { // 检测条件是否满足 if (item.CheckConditionAndSwitch()) break; } } private void ExitState(string parent, FSMStateNode nextState) { if (!current_states.ContainsKey(parent)) return; if (current_states[parent] == null) return; FSMStateNode currentState = current_states[parent]; if (nextState != null) currentState.nextState = nextState.data.name; if (nextState != null && nextState.data.CompareParent(currentState.data)) nextState.lastState = currentState.data.name; if (nextState != null) nextState.nextState = string.Empty; // 把下一个状态的值设置为空 currentState.OnExit(); // 移除状态 current_states.Remove(parent); // 判断一下当前状态是否子状态机 if (currentState.data.isSubStateMachine) { // 把子状态也退出掉 ExitState(currentState.data.name, nextState); } } private void EnterState(FSMStateNode state) { if (state == null) return; string parent = state.data.Parent; if (current_states.ContainsKey(parent)) current_states[parent] = state; else current_states.Add(parent, state); state?.OnEnter(); // 触发事件 FSMController.onStateChange?.Invoke(RuntimeFSMController.name, state.data.name); // 判断是否有子状态机 if (state.data.isSubStateMachine) { // 进入到子状态机的默认状态 FSMStateNodeData data = RuntimeFSMController.GetDefaultStateNodeData(state.data.name); if (data != null && states.ContainsKey(data.name)) EnterState(states[data.name]); } } public void SetBool(string name, bool v) { SetParamter(name, v ? 1 : 0, ParameterType.Bool); } public void SetFloat(string name, float v) { SetParamter(name, v, ParameterType.Float); } public void SetInt(string name, int v) { SetParamter(name, v, ParameterType.Int); } public void SetTrigger(string name) { FSMParameterData parameter; if (parameters.TryGetValue(name, out parameter)) { if (parameter.parameterType != ParameterType.Trigger) return; if (parameter.value == 1) { if (trigger_count.ContainsKey(name)) trigger_count[name]++; else trigger_count.Add(name, 1); } else { SetParamter(name, 1, ParameterType.Trigger); } } } /// /// 当Trigger触发后还原trigger /// /// internal void ClearTrigger(string name) { SetParamter(name, 0, ParameterType.Trigger); } public void ResetTrigger(string name) { if (trigger_count.ContainsKey(name)) trigger_count[name] = 0; ClearTrigger(name); } private void SetParamter(string name, float v, ParameterType type) { FSMParameterData parameter; if (parameters.TryGetValue(name, out parameter)) { if (parameter.parameterType == type) parameter.Value = v; } } internal float GetParamter(string name) { FSMParameterData parameter; if (parameters.TryGetValue(name, out parameter)) return parameter.value; return 0; } internal int GetTriggerCount(string name) { if (trigger_count.ContainsKey(name)) return trigger_count[name]; return 0; } public void Update() { current_states_array.Clear(); foreach (var item in current_states.Keys) { if (current_states[item] == null) continue; current_states_array.Add(current_states[item]); } foreach (var item in current_states_array) { if (!item.isRuning) continue; item.OnUpdate(); } // 更新Trigger UpdateTrigger(); } public void LateUpdate() { current_states_array.Clear(); foreach (var item in current_states.Keys) { if (current_states[item] == null) continue; current_states_array.Add(current_states[item]); } foreach (var item in current_states_array) { if (!item.isRuning) continue; item.OnLateUpdate(); } } public void FixedUpdate() { current_states_array.Clear(); foreach (var item in current_states.Keys) { if (current_states[item] == null) continue; current_states_array.Add(current_states[item]); } foreach (var item in current_states_array) { if (!item.isRuning) continue; item.OnFixedUpdate(); } } /// /// 添加计数 /// /// private void AddStateCount(string stateName) { if (state_count.ContainsKey(stateName)) state_count[stateName]++; else state_count.Add(stateName, 0); if (state_count[stateName] > 30) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("游戏物体:").Append(FSMController.gameObject.name) .Append("状态机:").Append(this.RuntimeFSMController.name).Append("检测到状态:"); foreach (var item in state_count.Keys) { if (state_count[item] >= 29) { stringBuilder.Append(item).Append(","); } } stringBuilder.Remove(stringBuilder.Length - 1, 1); stringBuilder.Append("之间频繁切换,请检查状态之间的过渡是否同时满足?请设置合理的状态切换条件!"); state_count.Clear(); throw new System.Exception(stringBuilder.ToString()); } } private void UpdateTrigger() { // 更新Trigger foreach (var item in trigger_count.Keys) { if (!trigerKeys.Contains(item)) trigerKeys.Add(item); } foreach (var item in trigerKeys) { if (!trigger_count.ContainsKey(item)) continue; if (trigger_count[item] > 0 && GetParamter(item) == 0) { SetParamter(item, 1, ParameterType.Trigger); trigger_count[item]--; if (trigger_count[item] < 0) trigger_count[item] = 0; } } } public FSMStateNode GetCurrentState(string parent) { if (current_states.ContainsKey(parent)) return current_states[parent]; return null; } internal void ResetParamter() { foreach (var item in parameter_default.Keys) { FSMParameterData parameter; if (parameters.TryGetValue(item, out parameter)) { parameter.Value = parameter_default[item]; } } } } }