You've already forked taptap2024_GJ_chidouren
444 lines
14 KiB
C#
444 lines
14 KiB
C#
|
|
using System.Collections.Generic;
|
||
|
|
using System.Text;
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
using UnityEditor;
|
||
|
|
#endif
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace XFFSM
|
||
|
|
{
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// RuntimeFSMController 运行时的示例
|
||
|
|
/// </summary>
|
||
|
|
public class RuntimeFSMControllerInstance
|
||
|
|
{
|
||
|
|
|
||
|
|
public string name;
|
||
|
|
|
||
|
|
|
||
|
|
public RuntimeFSMController RuntimeFSMController;
|
||
|
|
|
||
|
|
// 所有的参数
|
||
|
|
internal Dictionary<string, FSMParameterData> parameters = new Dictionary<string, FSMParameterData>();
|
||
|
|
|
||
|
|
[Tooltip("参数的默认值")]
|
||
|
|
internal Dictionary<string, float> parameter_default = new Dictionary<string, float>();
|
||
|
|
|
||
|
|
// 所有的状态
|
||
|
|
internal Dictionary<string, FSMStateNode> states = new Dictionary<string, FSMStateNode>();
|
||
|
|
|
||
|
|
internal List<FSMTransition> transitions = new List<FSMTransition>();
|
||
|
|
|
||
|
|
// 默认状态
|
||
|
|
internal FSMStateNode defaultState { get; private set; } = null;
|
||
|
|
|
||
|
|
private Dictionary<string, FSMStateNode> current_states = new Dictionary<string, FSMStateNode>();
|
||
|
|
|
||
|
|
private List<FSMStateNode> current_states_array = new List<FSMStateNode>();
|
||
|
|
|
||
|
|
// 当前的过渡
|
||
|
|
public FSMTransition currentTransition { get; private set; } = null;
|
||
|
|
|
||
|
|
public FSMController FSMController { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 状态切换计数(为了避免状态切换进入死循环)
|
||
|
|
/// </summary>
|
||
|
|
private Dictionary<string, int> state_count = new Dictionary<string, int>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当前的帧数
|
||
|
|
/// </summary>
|
||
|
|
private int currentSeconds = -1;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 记录Trigger触发的次数
|
||
|
|
/// </summary>
|
||
|
|
private Dictionary<string, int> trigger_count = new Dictionary<string, int>();
|
||
|
|
|
||
|
|
private List<string> trigerKeys = new List<string>();
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当Trigger触发后还原trigger
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="name"></param>
|
||
|
|
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();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 添加计数
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="stateName"></param>
|
||
|
|
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];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|