You've already forked taptap2024_GJ_chidouren
init
This commit is contained in:
8
Packages/com.xfkj.xffsm@357f537fea/Runtime/Const.meta
Normal file
8
Packages/com.xfkj.xffsm@357f537fea/Runtime/Const.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c60389c2e18d2b458d4b2fe57075894
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
20
Packages/com.xfkj.xffsm@357f537fea/Runtime/Const/FSMConst.cs
Normal file
20
Packages/com.xfkj.xffsm@357f537fea/Runtime/Const/FSMConst.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class FSMConst
|
||||
{
|
||||
|
||||
public const string anyState = "Any State";
|
||||
|
||||
public const string entryState = "Entry";
|
||||
|
||||
public const string up = "up"; // 上一层
|
||||
|
||||
public const int StateNodeWith = 200;
|
||||
public const int StateNodeHeight = 40;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b79137ac4899f240a27646af5a5b270
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
174
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMCondition.cs
Normal file
174
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMCondition.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
|
||||
public enum ConditionState
|
||||
{
|
||||
// 满足
|
||||
Meet,
|
||||
// 未满足
|
||||
NotMeet
|
||||
|
||||
}
|
||||
|
||||
public class FSMCondition
|
||||
{
|
||||
|
||||
#region 字段
|
||||
private FSMConditionData data;
|
||||
|
||||
private FSMParameterData parameter;
|
||||
|
||||
public Action onConditionMeet;
|
||||
|
||||
private static Dictionary<CompareType, IPamaterCompare> Compares = new Dictionary<CompareType, IPamaterCompare>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
public ConditionState State
|
||||
{
|
||||
get
|
||||
{
|
||||
if (compare.IsMeetCondition(this.parameter, data.targetValue))
|
||||
return ConditionState.Meet;
|
||||
else
|
||||
return ConditionState.NotMeet;
|
||||
}
|
||||
}
|
||||
|
||||
private IPamaterCompare compare => GetCompare(data.compareType);
|
||||
|
||||
public FSMParameterData Parameter => parameter;
|
||||
|
||||
#endregion
|
||||
|
||||
static FSMCondition() {
|
||||
InitCompares();
|
||||
}
|
||||
|
||||
public FSMCondition(FSMConditionData data, RuntimeFSMControllerInstance controller) {
|
||||
this.data = data;
|
||||
|
||||
if (controller.parameters.ContainsKey(data.parameterName)) {
|
||||
parameter = controller.parameters[this.data.parameterName];
|
||||
}
|
||||
|
||||
if (parameter != null)
|
||||
parameter.onValueChange += CheckParameterValueChange;
|
||||
|
||||
|
||||
// 检测条件
|
||||
CheckParameterValueChange();
|
||||
|
||||
}
|
||||
|
||||
public void CheckParameterValueChange()
|
||||
{
|
||||
// 判断条件有没有满足
|
||||
if (State == ConditionState.Meet)
|
||||
onConditionMeet?.Invoke();
|
||||
}
|
||||
|
||||
private static void InitCompares() {
|
||||
if (Compares.Count == 0) {
|
||||
Compares.Add(CompareType.Equal, new EqualCompare());
|
||||
Compares.Add(CompareType.Greater, new GreaterCompare());
|
||||
Compares.Add(CompareType.Less, new LessCompare());
|
||||
Compares.Add(CompareType.NotEqual, new NotEqualCompare());
|
||||
}
|
||||
}
|
||||
|
||||
public static IPamaterCompare GetCompare(CompareType type) {
|
||||
IPamaterCompare pamaterCompare;
|
||||
if ( Compares.TryGetValue(type,out pamaterCompare) ) {
|
||||
return pamaterCompare;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class FSMConditionGroup
|
||||
{
|
||||
|
||||
private List<FSMCondition> conditions = new List<FSMCondition>();
|
||||
|
||||
public Action onConditionMeet;
|
||||
|
||||
public bool IsMeet
|
||||
{
|
||||
get
|
||||
{
|
||||
// 当前过渡没有条件并且自动切换时,直接返回true,已满足
|
||||
if (transition.Empty && transition.AutoSwtich)
|
||||
return true;
|
||||
|
||||
if (ConditionCount == 0)
|
||||
return false;
|
||||
|
||||
foreach (var item in conditions)
|
||||
{
|
||||
if (item.State == ConditionState.NotMeet)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int ConditionCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (conditions == null)
|
||||
return 0;
|
||||
return conditions.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeFSMControllerInstance controller;
|
||||
|
||||
private FSMTransitionData transition;
|
||||
|
||||
public FSMConditionGroup(RuntimeFSMControllerInstance controller, List<FSMConditionData> conditions,FSMTransitionData transition)
|
||||
{
|
||||
this.controller = controller;
|
||||
this.transition = transition;
|
||||
this.conditions.Clear();
|
||||
foreach (var item in conditions)
|
||||
{
|
||||
FSMCondition condition = new FSMCondition(item, controller);
|
||||
condition.onConditionMeet += this.CheckIsMeet;
|
||||
this.conditions.Add(condition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//private void OnConditionMeet()
|
||||
//{
|
||||
// //Debug.Log("条件满足!");
|
||||
// DelayTools.DelayCall(CheckIsMeet);
|
||||
//}
|
||||
|
||||
private void CheckIsMeet()
|
||||
{
|
||||
if (IsMeet)
|
||||
onConditionMeet?.Invoke();
|
||||
}
|
||||
|
||||
internal void ResetTrigger() {
|
||||
foreach (var item in conditions)
|
||||
{
|
||||
if (item.Parameter.parameterType == ParameterType.Trigger)
|
||||
controller.ClearTrigger(item.Parameter.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a903871155618e84db2f5e13dc7718c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
549
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMController.cs
Normal file
549
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMController.cs
Normal file
@@ -0,0 +1,549 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class FSMController : MonoBehaviour
|
||||
{
|
||||
|
||||
#region 字段
|
||||
|
||||
[SerializeField]
|
||||
private List<RuntimeFSMController> _runtimeFSMController = new List<RuntimeFSMController>();
|
||||
|
||||
internal object userData;
|
||||
|
||||
private List<RuntimeFSMControllerInstance> Instances = new List<RuntimeFSMControllerInstance>();
|
||||
|
||||
private List<RuntimeFSMController> runtimeControllers = new List<RuntimeFSMController>();
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("是否在OnDisable时重置状态机")]
|
||||
[Header("是否在OnDisable时重置状态机")]
|
||||
private bool resetOnDisable = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 事件
|
||||
/// <summary>
|
||||
/// 初始化完成的回调
|
||||
/// </summary>
|
||||
public Action onInitFinish;
|
||||
/// <summary>
|
||||
/// 状态改变的回调 参数1:状态机名称 参数2:当前状态
|
||||
/// </summary>
|
||||
public Action<string,string> onStateChange;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态机执行的状态配置文件列表
|
||||
/// </summary>
|
||||
public List<RuntimeFSMController> RuntimeFSMController
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
return runtimeControllers;
|
||||
}
|
||||
|
||||
return _runtimeFSMController;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态机是否初始化完成
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
protected void Update()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
// 如果没有启动 就启动一下
|
||||
if(!item.Started)
|
||||
item.StartUp();
|
||||
|
||||
item.Update();
|
||||
}
|
||||
}
|
||||
|
||||
protected void LateUpdate()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.LateUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void FixedUpdate()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.FixedUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
if (resetOnDisable)
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
// 初始化
|
||||
public void Init(object userData)
|
||||
{
|
||||
if (Initialized)
|
||||
return;
|
||||
Instances.Clear();
|
||||
runtimeControllers.Clear();
|
||||
this.userData = userData;
|
||||
|
||||
foreach (var item in _runtimeFSMController)
|
||||
{
|
||||
if (item == null) continue;
|
||||
|
||||
RuntimeFSMControllerInstance instance = new RuntimeFSMControllerInstance(item, this);
|
||||
instance.StartUp();
|
||||
runtimeControllers.Add(instance.RuntimeFSMController);
|
||||
Instances.Add(instance);
|
||||
}
|
||||
Initialized = true;
|
||||
onInitFinish?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置bool类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <param name="v">值</param>
|
||||
public void SetBool(string name, bool v)
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Bool))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}",name, ParameterType.Bool);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetBool(name, v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
onInitFinish += () =>
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Bool))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Bool);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetBool(name, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置float类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <param name="v">值</param>
|
||||
public void SetFloat(string name, float v)
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Float))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Float);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetFloat(name, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
onInitFinish += () =>
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Float))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Float);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetFloat(name, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Int类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <param name="v">值</param>
|
||||
public void SetInt(string name, int v)
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Int))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Int);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetInt(name, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
onInitFinish += () =>
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Int))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Int);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetInt(name, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发Trigger
|
||||
/// </summary>
|
||||
/// <param name="name">Trigger名称</param>
|
||||
public void SetTrigger(string name)
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Trigger))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Trigger);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
|
||||
item.SetTrigger(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
onInitFinish += () =>
|
||||
{
|
||||
if (!IsContainParameter(name, ParameterType.Trigger))
|
||||
{
|
||||
Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", name, ParameterType.Trigger);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.SetTrigger(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 还原Trigger
|
||||
/// </summary>
|
||||
/// <param name="name">Trigger名称</param>
|
||||
public void ResetTrigger(string name) {
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
item.ResetTrigger(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Bool类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <returns></returns>
|
||||
public bool GetBool(string name)
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
if (item.GetParamter(name) == 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Float类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <returns></returns>
|
||||
public float GetFloat(string name )
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
float v = item.GetParamter(name);
|
||||
if (v != 0)
|
||||
return v;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Int类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <returns></returns>
|
||||
public int GetInt(string name)
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
int v = (int)(item.GetParamter(name));
|
||||
if (v != 0)
|
||||
return v;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Trigger类型参数的值
|
||||
/// </summary>
|
||||
/// <param name="name">参数名称</param>
|
||||
/// <returns></returns>
|
||||
public bool GetTrigger(string name )
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
if (item.GetTriggerCount(name) > 0 || item.GetParamter(name) == 1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsContainParameter(string name,ParameterType type)
|
||||
{
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
if(item.parameters.ContainsKey(name) && item.parameters[name].parameterType == type)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行时添加并执行状态配置文件
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
public void AddRuntimeFSMController(RuntimeFSMController controller) {
|
||||
if (_runtimeFSMController.Contains(controller))
|
||||
{
|
||||
Debug.LogWarningFormat("状态机:{0}已经执行,请勿重复添加!", controller.name);
|
||||
return; // 说明已经添加了该状态机
|
||||
}
|
||||
_runtimeFSMController.Add(controller);
|
||||
|
||||
// 如果没有初始化完成 不需要处理 在初始化的时候会处理
|
||||
if (Initialized)
|
||||
{
|
||||
// 如果初始化完成了 启动这个状态
|
||||
RuntimeFSMControllerInstance controllerInstance = new RuntimeFSMControllerInstance(controller, this);
|
||||
controllerInstance.StartUp();
|
||||
runtimeControllers.Add(controllerInstance.RuntimeFSMController);
|
||||
Instances.Add(controllerInstance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行时移除状态机配置文件
|
||||
/// </summary>
|
||||
/// <param name="index">配置文件下标</param>
|
||||
public void RemoveRuntimeFSMController(int index) {
|
||||
if (index < 0 || index >= RuntimeFSMController.Count) return;
|
||||
RuntimeFSMController controller = RuntimeFSMController[index];
|
||||
RuntimeFSMController.RemoveAt(index);
|
||||
|
||||
for (int i = 0; i < Instances.Count; i++)
|
||||
{
|
||||
if (Instances[i].RuntimeFSMController == controller)
|
||||
{
|
||||
Instances[i].Close();
|
||||
Instances.Remove(Instances[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前正在执行的状态信息
|
||||
/// </summary>
|
||||
/// <param name="index">状态配置下标</param>
|
||||
/// <param name="subStateName">子状态机名称(默认:空)</param>
|
||||
/// <returns></returns>
|
||||
public FSMStateNode GetCurrentStateInfo(int index,string subStateName = "")
|
||||
{
|
||||
if (index < 0 || index >= Instances.Count) return null;
|
||||
return Instances[index].GetCurrentState(subStateName);
|
||||
}
|
||||
|
||||
public FSMStateNode GetCurrentStateInfo(string controllerName, string subStateName = "") {
|
||||
|
||||
if (string.IsNullOrEmpty(controllerName))
|
||||
return null;
|
||||
|
||||
foreach (var item in Instances)
|
||||
{
|
||||
if (item.name.Equals(controllerName))
|
||||
return item.GetCurrentState(subStateName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前的状态切换信息
|
||||
/// </summary>
|
||||
/// <param name="controller"></param>
|
||||
/// <returns></returns>
|
||||
public FSMTransition GetCurrentTransition(int index)
|
||||
{
|
||||
if (index < 0 || index >= Instances.Count) return null;
|
||||
return Instances[index].currentTransition;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 静态字段
|
||||
|
||||
private static Dictionary<string,FSMController> fsms = new Dictionary<string,FSMController>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region 静态属性
|
||||
|
||||
|
||||
private static Transform FSMParent { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 静态方法
|
||||
|
||||
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
static void InitFSMController()
|
||||
{
|
||||
fsms.Clear();
|
||||
|
||||
GameObject obj = new GameObject("FSMControllers");
|
||||
DontDestroyOnLoad(obj);
|
||||
FSMParent = obj.transform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动状态(适用于没有具体游戏物体的状态管理,例如:游戏状态)
|
||||
/// </summary>
|
||||
/// <param name="fsmName">状态机名称</param>
|
||||
/// <param name="fsm">状态配置文件</param>
|
||||
/// <param name="userData">自定义参数或数据</param>
|
||||
/// <returns></returns>
|
||||
public static FSMController StartupFSM(string fsmName,RuntimeFSMController fsm,object userData = null)
|
||||
{
|
||||
if (fsms.ContainsKey(fsmName)) return null;
|
||||
GameObject obj = new GameObject(fsmName);
|
||||
obj.transform.SetParent(FSMParent,false);
|
||||
FSMController controller = obj.AddComponent<FSMController>();
|
||||
controller.userData = userData;
|
||||
controller.AddRuntimeFSMController(fsm);
|
||||
fsms.Add(fsmName, controller);
|
||||
return controller;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询通过FSMController.StartupFSM启动的状态机
|
||||
/// </summary>
|
||||
/// <param name="fsmName">状态机名称</param>
|
||||
/// <returns></returns>
|
||||
public static FSMController GetFSM(string fsmName)
|
||||
{
|
||||
if(fsms.ContainsKey(fsmName))
|
||||
return fsms[fsmName];
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除通过FSMController.StartupFSM启动的状态机
|
||||
/// </summary>
|
||||
/// <param name="fsmName">状态机名称</param>
|
||||
public static void RemoveFSM(string fsmName)
|
||||
{
|
||||
if (!fsms.ContainsKey(fsmName)) return;
|
||||
FSMController controller = fsms[fsmName];
|
||||
fsms.Remove(fsmName);
|
||||
Destroy(controller.gameObject);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fe35428f651da84eb46e75a300ce29d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
87
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMState.cs
Normal file
87
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMState.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态基类
|
||||
/// </summary>
|
||||
public abstract class FSMState
|
||||
{
|
||||
|
||||
#region 字段
|
||||
/// <summary>
|
||||
/// 状态控制器
|
||||
/// </summary>
|
||||
public FSMController controller;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态信息
|
||||
/// </summary>
|
||||
public FSMStateNode currentStateInfo;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义数据(通过FSMController.StartupFSM()启动状态机传递自定义数据)
|
||||
/// </summary>
|
||||
public object userData;
|
||||
|
||||
/// <summary>
|
||||
/// 上一个状态的名称
|
||||
/// </summary>
|
||||
public string lastState;
|
||||
|
||||
/// <summary>
|
||||
/// 将要切换的下一个状态的名称(该字段仅在状态将要退出(OnExit)时有值)
|
||||
/// </summary>
|
||||
public string nextState;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 属性
|
||||
|
||||
public Transform transform => controller != null ? controller.transform : null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 当第一次进入该状态时调用,该方法仅调用一次(初始化相关操作推荐放该方法中)
|
||||
/// </summary>
|
||||
public virtual void OnCreate() {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当状态进入时执行
|
||||
/// </summary>
|
||||
public virtual void OnEnter() {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当状态退出时执行
|
||||
/// </summary>
|
||||
public virtual void OnExit() { }
|
||||
|
||||
/// <summary>
|
||||
/// 每帧执行
|
||||
/// </summary>
|
||||
public virtual void OnUpdate() { }
|
||||
|
||||
/// <summary>
|
||||
/// FixedUpdate时执行
|
||||
/// </summary>
|
||||
public virtual void OnFixedUpdate() { }
|
||||
|
||||
/// <summary>
|
||||
/// LateUpdate时执行
|
||||
/// </summary>
|
||||
public virtual void OnLateUpdate() {
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
11
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMState.cs.meta
Normal file
11
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMState.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76fb38d6317f3ae4293c1cd20b16aa82
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
116
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMStateNode.cs
Normal file
116
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMStateNode.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态节点
|
||||
/// </summary>
|
||||
public class FSMStateNode
|
||||
{
|
||||
#region 字段
|
||||
/// <summary>
|
||||
/// 状态数据
|
||||
/// </summary>
|
||||
public FSMStateNodeData data;
|
||||
internal RuntimeFSMControllerInstance instance;
|
||||
private List<FSMState> states = new List<FSMState>();
|
||||
|
||||
internal string lastState;
|
||||
internal string nextState;
|
||||
/// <summary>
|
||||
/// 是否正在执行中
|
||||
/// </summary>
|
||||
internal bool isRuning = false;
|
||||
|
||||
internal bool isFirstEnter = true;
|
||||
|
||||
[Tooltip("当前状态名称Hash,可通过方法Animator.StringToHash()转换!")]
|
||||
public int nameHash;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
internal FSMStateNode(FSMStateNodeData data,RuntimeFSMControllerInstance instance)
|
||||
{
|
||||
this.data = data;
|
||||
this.instance = instance;
|
||||
nameHash = Animator.StringToHash(data.name);
|
||||
|
||||
states.Clear();
|
||||
foreach (var item in this.data.StateScripts)
|
||||
{
|
||||
Type type = AssemblyTools.GetType(item.className);
|
||||
FSMState state = null;
|
||||
if (type != null)
|
||||
state = Activator.CreateInstance(type) as FSMState;
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
state.controller = instance.FSMController;
|
||||
state.userData = instance.FSMController.userData;
|
||||
state.currentStateInfo = this;
|
||||
states.Add(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal void OnEnter()
|
||||
{
|
||||
isRuning = true;
|
||||
foreach (var item in this.states)
|
||||
{
|
||||
item.lastState = lastState;
|
||||
item.nextState = nextState;
|
||||
|
||||
if (isFirstEnter)
|
||||
item.OnCreate(); // 调用 OnCreate 的方法
|
||||
|
||||
item.OnEnter();
|
||||
}
|
||||
|
||||
isFirstEnter = false;
|
||||
}
|
||||
|
||||
internal void OnExit()
|
||||
{
|
||||
foreach (var item in this.states)
|
||||
{
|
||||
item.lastState = lastState;
|
||||
item.nextState = nextState;
|
||||
item.OnExit();
|
||||
}
|
||||
isRuning = false;
|
||||
}
|
||||
|
||||
internal void OnUpdate()
|
||||
{
|
||||
foreach (var item in this.states)
|
||||
{
|
||||
item.OnUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnFixedUpdate()
|
||||
{
|
||||
foreach (var item in this.states)
|
||||
{
|
||||
item.OnFixedUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnLateUpdate()
|
||||
{
|
||||
foreach (var item in this.states)
|
||||
{
|
||||
item.OnLateUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb1a5ad5f0c611f428f7d98455d4ed3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
146
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMTransition.cs
Normal file
146
Packages/com.xfkj.xffsm@357f537fea/Runtime/FSMTransition.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态之间的过渡
|
||||
/// </summary>
|
||||
public class FSMTransition
|
||||
{
|
||||
#region 字段
|
||||
private FSMTransitionData data;
|
||||
private RuntimeFSMControllerInstance controller;
|
||||
private FSMStateNode toState;
|
||||
|
||||
public List<FSMConditionGroup> condition_groups;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 过渡数据
|
||||
/// </summary>
|
||||
public FSMTransitionData Data => data;
|
||||
|
||||
/// <summary>
|
||||
/// 过渡目标状态
|
||||
/// </summary>
|
||||
public FSMStateNode ToState => toState;
|
||||
|
||||
// 条件是否已经满足
|
||||
internal bool IsMeet
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果过渡没有条件认为条件满足,可以切换状态
|
||||
//if (conditions.Count == 0) return true;
|
||||
|
||||
// 判断是不是所有的条件都满足了
|
||||
//foreach (var item in conditions)
|
||||
//{
|
||||
// if (item.state == ConditionState.NotMeet) return false;
|
||||
//}
|
||||
|
||||
if(!ConditionGroupMeet())
|
||||
return false;
|
||||
|
||||
if (toState == null) {
|
||||
Debug.LogError("查询目标状态失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
FSMStateNodeData from = controller.RuntimeFSMController.GetStateNodeData(data.fromStateName);
|
||||
string parent = from.Parent;
|
||||
FSMStateNode currentState = controller.GetCurrentState(parent);
|
||||
|
||||
if (currentState == null) return false;
|
||||
|
||||
if (!data.fromStateName.Equals(currentState.data.name))
|
||||
{
|
||||
// AnyState
|
||||
if (!from.IsAnyState) return false;
|
||||
|
||||
// 判断当前的状态 跟 目标状态是不是一个
|
||||
if (currentState.data.name.Equals(data.toStateName)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
internal FSMTransition(RuntimeFSMControllerInstance controller, FSMTransitionData data) {
|
||||
this.data = data;
|
||||
this.controller = controller;
|
||||
|
||||
//this.conditions = new List<FSMCondition>();
|
||||
|
||||
this.condition_groups = new List<FSMConditionGroup>();
|
||||
|
||||
FSMConditionGroup group = new FSMConditionGroup(controller, this.data.conditions,data);
|
||||
group.onConditionMeet += this.CheckCondition;
|
||||
condition_groups.Add(group);
|
||||
|
||||
foreach (var item in data.group_conditions)
|
||||
{
|
||||
FSMConditionGroup condition_group = new FSMConditionGroup(controller, item.conditions,data);
|
||||
condition_group.onConditionMeet += this.CheckCondition;
|
||||
condition_groups.Add(condition_group);
|
||||
}
|
||||
|
||||
if ( controller.states.ContainsKey(data.toStateName) ) {
|
||||
toState = controller.states[data.toStateName];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 检测条件是否满足
|
||||
private void CheckCondition()
|
||||
{
|
||||
CheckConditionAndSwitch();
|
||||
}
|
||||
|
||||
// 检测条件是不是都满足了
|
||||
internal bool CheckConditionAndSwitch()
|
||||
{
|
||||
bool isMeet = IsMeet;
|
||||
if (isMeet)
|
||||
{
|
||||
// reset trigger
|
||||
ResetTrigger();
|
||||
// 切换状态
|
||||
controller.SwitchState(toState,this);
|
||||
}
|
||||
return isMeet;
|
||||
}
|
||||
|
||||
private void ResetTrigger()
|
||||
{
|
||||
foreach (var item in condition_groups)
|
||||
{
|
||||
item.ResetTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConditionGroupMeet()
|
||||
{
|
||||
foreach (var item in condition_groups)
|
||||
{
|
||||
if (item.IsMeet)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e79f402e7c3f8d469bdc13c274859ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fa07ed66e4419d49a4d1055157deb05
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class EqualCompare : IPamaterCompare
|
||||
{
|
||||
public bool IsMeetCondition(FSMParameterData parameter, float v)
|
||||
{
|
||||
if (parameter == null) return false;
|
||||
return parameter.Value.Equals(v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e49ee6d84fabb8840a7ab213d3e6352a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class GreaterCompare : IPamaterCompare
|
||||
{
|
||||
public bool IsMeetCondition(FSMParameterData parameter, float v)
|
||||
{
|
||||
if(parameter == null) return false;
|
||||
return parameter.Value.CompareTo(v) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d3f99229e585164c9a62664c6899cce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public interface IPamaterCompare
|
||||
{
|
||||
bool IsMeetCondition(FSMParameterData parameter,float v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb974504762931849a213e3a03b6ecfa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class LessCompare : IPamaterCompare
|
||||
{
|
||||
public bool IsMeetCondition(FSMParameterData parameter, float v)
|
||||
{
|
||||
if (parameter == null) return false;
|
||||
return parameter.Value.CompareTo(v) == -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 893c2117a43440640bfcc085acd4551c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class NotEqualCompare : IPamaterCompare
|
||||
{
|
||||
public bool IsMeetCondition(FSMParameterData parameter, float v)
|
||||
{
|
||||
if (parameter == null) return false;
|
||||
return !parameter.Value.Equals(v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c56709ab9ef376847926592b2a888083
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.xfkj.xffsm@357f537fea/Runtime/Others.meta
Normal file
8
Packages/com.xfkj.xffsm@357f537fea/Runtime/Others.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 984698abbbef91847836af5cbcc6e545
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 程序集工具
|
||||
/// </summary>
|
||||
public class AssemblyTools
|
||||
{
|
||||
|
||||
private static Dictionary<string, Type> typeCaches = new Dictionary<string, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 根据名称来获取类型
|
||||
/// </summary>
|
||||
/// <param name="classFullName">类名(含命名空间)</param>
|
||||
/// <returns></returns>
|
||||
internal static Type GetType(string classFullName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(classFullName)) return null;
|
||||
|
||||
if (typeCaches.ContainsKey(classFullName) && typeCaches[classFullName] != null) return typeCaches[classFullName];
|
||||
|
||||
typeCaches.Remove(classFullName);
|
||||
|
||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
Assembly assembly = assemblies[i];
|
||||
|
||||
Type type = assembly.GetType(classFullName);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
typeCaches.Add(classFullName, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeCaches.ContainsKey(classFullName))
|
||||
return typeCaches[classFullName];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有状态脚本(仅编辑器有效)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<MonoScript> GetAllStatesType()
|
||||
{
|
||||
List<MonoScript> states = new List<MonoScript>();
|
||||
|
||||
string[] scripts = AssetDatabase.FindAssets("t:Script");
|
||||
|
||||
foreach (var item in scripts)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(item);
|
||||
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||
|
||||
if (script == null) continue;
|
||||
|
||||
Type type = script.GetClass();
|
||||
|
||||
if (type == null) continue;
|
||||
|
||||
if(type.IsSubclassOf(typeof(FSMState)))
|
||||
states.Add(script);
|
||||
//if (IsBaseByClass(type, typeof(FSMState)))
|
||||
//{
|
||||
// states.Add(script);
|
||||
//}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据状态脚本全名称获取脚本guid(仅编辑器有效)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetGUIDByStateClassFullName(string fullName)
|
||||
{
|
||||
List<MonoScript> scripts = GetAllStatesType();
|
||||
|
||||
foreach (var item in scripts)
|
||||
{
|
||||
if (item.GetClass() != null && item.GetClass().FullName.Equals(fullName))
|
||||
{
|
||||
return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(item));
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d8545ba550f54945b8667f6e2af42fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
/// <summary>
|
||||
/// EditorApplication工具
|
||||
/// </summary>
|
||||
internal class EditorApplicationTool
|
||||
{
|
||||
// Fix编码
|
||||
/// <summary>
|
||||
/// 默认是运行中
|
||||
/// </summary>
|
||||
private static bool _isPlaying = true;
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前编辑器是否处于运行状态(UnityEngine.Application.isPlaying在停止运行编辑器时触发OnDestroy时仍返回true)
|
||||
/// </summary>
|
||||
public static bool isPlaying
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged += EditorApplication_playModeStateChanged;
|
||||
#endif
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
private static void EditorApplication_playModeStateChanged(PlayModeStateChange obj)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case PlayModeStateChange.ExitingPlayMode:
|
||||
_isPlaying = false;
|
||||
break;
|
||||
case PlayModeStateChange.ExitingEditMode:
|
||||
_isPlaying = true;
|
||||
break;
|
||||
case PlayModeStateChange.EnteredEditMode:
|
||||
_isPlaying = false;
|
||||
break;
|
||||
case PlayModeStateChange.EnteredPlayMode:
|
||||
_isPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ba0470d919012b4fa362e8d0f38d23f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67cc9d9a9ee78614f87fdad6928a73ef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
|
||||
public enum CompareType {
|
||||
|
||||
Greater = 0,
|
||||
Less,
|
||||
Equal,
|
||||
NotEqual,
|
||||
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class FSMConditionData
|
||||
{
|
||||
|
||||
public float targetValue;
|
||||
|
||||
public string parameterName;
|
||||
|
||||
public CompareType compareType;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2becbadd938f3145bb5a6adec0f834a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
|
||||
public enum ParameterType {
|
||||
Float = 0,
|
||||
Int,
|
||||
Bool,
|
||||
Trigger
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class FSMParameterData
|
||||
{
|
||||
#region 字段
|
||||
public string name;
|
||||
|
||||
public float value;
|
||||
|
||||
public ParameterType parameterType;
|
||||
|
||||
public Action onValueChange;
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
public float Value {
|
||||
get { return value; }
|
||||
set {
|
||||
|
||||
if (this.value == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
onValueChange?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3e41aa1d7814c14592ab6fe0f173093
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,337 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
[System.Serializable]
|
||||
public class FSMStateScriptInfo
|
||||
{
|
||||
public string className;
|
||||
public string guid;
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class FSMStateNodeData
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public Rect rect;
|
||||
|
||||
public void AddStateScript(MonoScript script)
|
||||
{
|
||||
string guid = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(script));
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
throw new System.Exception(string.Format("脚本添加失败,获取guid失败:{0}",script.name));
|
||||
foreach (var item in StateScripts)
|
||||
{
|
||||
if (item.guid.Equals(guid))
|
||||
throw new System.Exception("脚本重复添加!");
|
||||
}
|
||||
FSMStateScriptInfo info = new FSMStateScriptInfo();
|
||||
info.guid = guid;
|
||||
Type type = script.GetClass();
|
||||
if (type != null)
|
||||
{
|
||||
info.className = type.FullName;
|
||||
}
|
||||
StateScripts.Add(info);
|
||||
}
|
||||
|
||||
public void RefreshStateScripts(RuntimeFSMController controller)
|
||||
{
|
||||
|
||||
//EditorApplication.
|
||||
|
||||
List<FSMStateScriptInfo> invalid = new List<FSMStateScriptInfo>();
|
||||
|
||||
foreach (var item in StateScripts)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.guid) && !string.IsNullOrEmpty(item.className))
|
||||
item.guid = AssemblyTools.GetGUIDByStateClassFullName(item.className);
|
||||
|
||||
string path = AssetDatabase.GUIDToAssetPath(item.guid);
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
invalid.Add(item);
|
||||
continue;
|
||||
}
|
||||
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||
if (script == null)
|
||||
{
|
||||
//Debug.LogFormat("添加无效脚本:{0} guid:{1}", script.name, path);
|
||||
//invalid.Add(item);
|
||||
continue;
|
||||
}
|
||||
Type type = script.GetClass();
|
||||
// 如果等于空或者没有继承自FSMState视为无效
|
||||
if (type == null)
|
||||
{
|
||||
//invalid.Add(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
item.className = type.FullName;
|
||||
}
|
||||
|
||||
// 移除无效的脚本 ( 这些脚本可能已经被删除了 )
|
||||
foreach (var item in invalid)
|
||||
{
|
||||
StateScripts.Remove(item);
|
||||
}
|
||||
|
||||
if(controller != null)
|
||||
controller.Save();
|
||||
}
|
||||
|
||||
public void RemoveStateScript(MonoScript script)
|
||||
{
|
||||
Type type = script.GetClass();
|
||||
if (type == null) return;
|
||||
|
||||
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(script));
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
throw new System.Exception(string.Format("脚本添加失败,获取guid失败:{0}", script.name));
|
||||
|
||||
FSMStateScriptInfo info = null;
|
||||
|
||||
foreach (var item in StateScripts)
|
||||
{
|
||||
if (item.guid.Equals(guid)) {
|
||||
info = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info == null) return;
|
||||
|
||||
StateScripts.Remove(info);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 是否是默认状态
|
||||
/// </summary>
|
||||
public bool defaultState;
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string name;
|
||||
|
||||
/// <summary>
|
||||
/// 状态脚本的名称
|
||||
/// </summary>
|
||||
public List<FSMStateScriptInfo> StateScripts = new List<FSMStateScriptInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态的父节点名称
|
||||
/// </summary>
|
||||
public List<string> parents;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为子状态机
|
||||
/// </summary>
|
||||
public bool isSubStateMachine = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为内置状态
|
||||
/// </summary>
|
||||
public bool isBuildInState = false;
|
||||
|
||||
/// <summary>
|
||||
/// 内置状态名称
|
||||
/// </summary>
|
||||
public string buildInStateName = null;
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前状态是否为Any状态
|
||||
/// </summary>
|
||||
public bool IsAnyState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (name.Equals(FSMConst.anyState))
|
||||
return true;
|
||||
|
||||
if (isBuildInState && buildInStateName.Equals(FSMConst.anyState))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前状态是否Entry状态
|
||||
/// </summary>
|
||||
public bool IsEntryState
|
||||
{
|
||||
get {
|
||||
|
||||
if (name.Equals(FSMConst.entryState))
|
||||
return true;
|
||||
|
||||
if (isBuildInState && buildInStateName.Equals(FSMConst.entryState))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否为返回上一层的按钮
|
||||
/// </summary>
|
||||
public bool IsUpState
|
||||
{
|
||||
get {
|
||||
|
||||
if (isBuildInState && buildInStateName.Equals(FSMConst.up))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAnyState)
|
||||
return FSMConst.anyState;
|
||||
if (IsEntryState)
|
||||
return FSMConst.entryState;
|
||||
if (IsUpState)
|
||||
{
|
||||
if (parents.Count > 1)
|
||||
return string.Format("(Up){0}", parents[parents.Count - 2]);
|
||||
else
|
||||
return "(Up)Base Layer";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public string ParentPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (parents == null || parents.Count == 0) return string.Empty;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < parents.Count; i++) {
|
||||
sb.Append(parents[i]);
|
||||
if (i < parents.Count - 1)
|
||||
sb.Append("/");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string NextParentPath {
|
||||
get
|
||||
{
|
||||
List<string> next_parents = new List<string>();
|
||||
|
||||
if (parents != null && parents.Count != 0)
|
||||
next_parents.AddRange(parents);
|
||||
|
||||
next_parents.Add(name);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < next_parents.Count; i++)
|
||||
{
|
||||
sb.Append(next_parents[i]);
|
||||
if (i < next_parents.Count - 1)
|
||||
sb.Append("/");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string Parent
|
||||
{
|
||||
get {
|
||||
if (parents == null || parents.Count == 0) return string.Empty;
|
||||
|
||||
return parents[parents.Count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool CompareParent(FSMStateNodeData node)
|
||||
{
|
||||
if (BaseLayer() && node.BaseLayer()) return true;
|
||||
|
||||
if(parents == null || node.parents == null) return false;
|
||||
|
||||
if (node.parents.Count != this.parents.Count) return false;
|
||||
|
||||
for (int i = 0; i < parents.Count; i++)
|
||||
{
|
||||
if (!parents[i].Equals(node.parents[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CompareParent(List<string> parents) {
|
||||
|
||||
if (BaseLayer()) return parents == null || parents.Count == 0;
|
||||
|
||||
if (parents == null || this.parents == null) return false;
|
||||
|
||||
if (parents.Count != this.parents.Count) return false;
|
||||
|
||||
for (int i = 0; i < this.parents.Count; i++)
|
||||
{
|
||||
if (!this.parents[i].Equals(parents[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BaseLayer()
|
||||
{
|
||||
return this.parents == null || this.parents.Count == 0;
|
||||
}
|
||||
|
||||
|
||||
public bool ContainsParent(string parent)
|
||||
{
|
||||
if(BaseLayer()) return false;
|
||||
return parents.Contains(parent);
|
||||
}
|
||||
|
||||
public bool BelongToParent(string parent)
|
||||
{
|
||||
if(BaseLayer()) return false;
|
||||
return parents[parents.Count - 1].Equals(parent);
|
||||
}
|
||||
|
||||
public void RenameParent(string oldParent, string newName) {
|
||||
int index = parents.IndexOf(oldParent);
|
||||
parents[index] = newName;
|
||||
}
|
||||
|
||||
public List<string> GetParent() {
|
||||
List<string> parents = new List<string>();
|
||||
if (parents == null) return parents;
|
||||
parents.AddRange(this.parents);
|
||||
return parents;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9a895c087d06e44eb52451b523e7fea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public class GroupCondition
|
||||
{
|
||||
public List<FSMConditionData> conditions = new List<FSMConditionData>();
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class FSMTransitionData
|
||||
{
|
||||
|
||||
public string fromStateName;
|
||||
public string toStateName;
|
||||
|
||||
public string Key
|
||||
{
|
||||
get {
|
||||
return string.Format("{0}:{1}",fromStateName,toStateName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<FSMConditionData> conditions = new List<FSMConditionData>();
|
||||
|
||||
public List<GroupCondition> group_conditions = new List<GroupCondition>();
|
||||
|
||||
public bool AutoSwtich = false;
|
||||
|
||||
public bool Empty
|
||||
{
|
||||
get {
|
||||
|
||||
if(conditions.Count != 0)
|
||||
return false;
|
||||
|
||||
foreach (GroupCondition condition in group_conditions) {
|
||||
if(condition.conditions.Count != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a61269aeb473d154e9b6c9e33e8ec616
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,321 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XFFSM
|
||||
{
|
||||
public class RuntimeFSMController : ScriptableObject
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 背景线的中心点坐标
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public Vector3 viewPosition = new Vector3(100,100,0);
|
||||
[HideInInspector]
|
||||
public Vector3 viewScale = Vector3.one * 0.8f;
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户选择的状态机层级
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public List<string> Layers = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 实例化该对象的源文件的GUID
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public string originGUID;
|
||||
|
||||
public void AddLayer(string layer)
|
||||
{
|
||||
if(Layers.Contains(layer))
|
||||
return;
|
||||
Layers.Add(layer);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void RemoveLayer(int index, int count)
|
||||
{
|
||||
Layers.RemoveRange(index, count);
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空当前用户选择的状态层级
|
||||
/// </summary>
|
||||
public void ClearLayer()
|
||||
{
|
||||
Layers.Clear();
|
||||
Save();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 所有的状态
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public List<FSMStateNodeData> states = new List<FSMStateNodeData>();
|
||||
|
||||
/// <summary>
|
||||
/// 所有的参数
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public List<FSMParameterData> parameters = new List<FSMParameterData>();
|
||||
|
||||
/// <summary>
|
||||
/// 保存所有的过渡
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public List<FSMTransitionData> transitions = new List<FSMTransitionData>();
|
||||
|
||||
|
||||
private Dictionary<string,FSMStateNodeData> states_dic = new Dictionary<string, FSMStateNodeData> ();
|
||||
private Dictionary<string,FSMParameterData> parameters_dic = new Dictionary<string, FSMParameterData>();
|
||||
private Dictionary<string, FSMStateNodeData> default_states_dic = new Dictionary<string, FSMStateNodeData>();
|
||||
private Dictionary<string, FSMTransitionData> transitions_dic = new Dictionary<string, FSMTransitionData>();
|
||||
|
||||
|
||||
public FSMStateNodeData GetStateNodeData(string name) {
|
||||
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
if (states_dic.Count == 0) {
|
||||
foreach (FSMStateNodeData state in states)
|
||||
{
|
||||
if (states_dic.ContainsKey(state.name))
|
||||
throw new System.Exception(string.Format("状态名称重复:{0}", state.name));
|
||||
states_dic.Add (state.name, state);
|
||||
}
|
||||
}
|
||||
|
||||
if(states_dic.ContainsKey(name))
|
||||
return states_dic[name];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public FSMParameterData GetParameterData(string name)
|
||||
{
|
||||
if(name == null)
|
||||
return null;
|
||||
|
||||
if (parameters_dic.Count == 0) {
|
||||
foreach (var item in parameters)
|
||||
{
|
||||
if (parameters_dic.ContainsKey(item.name))
|
||||
throw new System.Exception(string.Format("参数名称重复:{0}", item.name));
|
||||
parameters_dic.Add (item.name, item);
|
||||
}
|
||||
}
|
||||
|
||||
if(parameters_dic.ContainsKey(name))
|
||||
return parameters_dic[name];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某一个层级的默认状态
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
/// <returns></returns>
|
||||
public FSMStateNodeData GetDefaultStateNodeData(string parent)
|
||||
{
|
||||
if (parent == null)
|
||||
return null;
|
||||
|
||||
if (default_states_dic.Count == 0)
|
||||
{
|
||||
foreach (var item in states)
|
||||
{
|
||||
if (!item.defaultState) continue;
|
||||
if (default_states_dic.ContainsKey(item.Parent))
|
||||
throw new System.Exception(string.Format("检测到层级:{0}有多个默认状态!",item.Parent));
|
||||
default_states_dic.Add(item.Parent, item);
|
||||
}
|
||||
}
|
||||
|
||||
if(default_states_dic.ContainsKey(parent))
|
||||
return default_states_dic[parent];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public FSMTransitionData GetTransitionData(string from, string to) {
|
||||
|
||||
if (transitions_dic.Count == 0) {
|
||||
foreach (var item in transitions)
|
||||
{
|
||||
transitions_dic.Add(item.Key, item);
|
||||
}
|
||||
}
|
||||
|
||||
string key = string.Format("{0}:{1}",from,to);
|
||||
|
||||
if(transitions_dic.ContainsKey(key))
|
||||
return transitions_dic[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
private Dictionary<string, List<FSMStateNodeData>> current_show_states = new Dictionary<string, List<FSMStateNodeData>>();
|
||||
private Dictionary<string, List<FSMTransitionData>> current_show_transitions = new Dictionary<string, List<FSMTransitionData>>();
|
||||
|
||||
|
||||
|
||||
public void AddState(FSMStateNodeData state) {
|
||||
ClearCache();
|
||||
states.Add(state);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void RemoveState(FSMStateNodeData state)
|
||||
{
|
||||
ClearCache();
|
||||
states.Remove(state);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void AddParameters(FSMParameterData data) {
|
||||
ClearCache();
|
||||
parameters.Add(data);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void RemoveParameters(FSMParameterData data) {
|
||||
ClearCache();
|
||||
parameters.Remove(data);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void AddTransition(FSMTransitionData data) {
|
||||
ClearCache();
|
||||
transitions.Add(data);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void RemoveTransition(FSMTransitionData data) {
|
||||
ClearCache();
|
||||
transitions.Remove(data);
|
||||
Save();
|
||||
}
|
||||
|
||||
|
||||
public void ClearCache()
|
||||
{
|
||||
states_dic.Clear();
|
||||
parameters_dic.Clear();
|
||||
default_states_dic.Clear();
|
||||
current_show_states.Clear();
|
||||
current_show_transitions.Clear();
|
||||
transitions_dic.Clear();
|
||||
}
|
||||
|
||||
|
||||
public List<FSMStateNodeData> GetCurrentShowStateNodeData(string parent)
|
||||
{
|
||||
|
||||
if (parent == null)
|
||||
return null;
|
||||
|
||||
if (current_show_states.Count == 0)
|
||||
{
|
||||
foreach (var item in states)
|
||||
{
|
||||
if (current_show_states.ContainsKey(item.Parent))
|
||||
{
|
||||
current_show_states[item.Parent].Add(item);
|
||||
}
|
||||
else {
|
||||
current_show_states.Add(item.Parent,new List<FSMStateNodeData> { item });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_show_states.ContainsKey(parent))
|
||||
{
|
||||
List<FSMStateNodeData> current_show_state = current_show_states[parent];
|
||||
if (current_show_state.Count == 0)
|
||||
ClearLayer();
|
||||
return current_show_state;
|
||||
}
|
||||
|
||||
ClearLayer();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<FSMTransitionData> GetCurrentShowTransitionData(string parent)
|
||||
{
|
||||
|
||||
if (parent == null)
|
||||
return null;
|
||||
|
||||
if (current_show_transitions.Count == 0) {
|
||||
foreach (var item in transitions)
|
||||
{
|
||||
FSMStateNodeData from = GetStateNodeData(item.fromStateName);
|
||||
FSMStateNodeData to = GetStateNodeData(item.toStateName);
|
||||
|
||||
if (!from.Parent.Equals(to.Parent))
|
||||
throw new System.Exception(string.Format("过渡的起始状态{0}和结束状态{1}不在同一个层级!",from.name,to.name));
|
||||
|
||||
if (current_show_transitions.ContainsKey(from.Parent))
|
||||
current_show_transitions[from.Parent].Add(item);
|
||||
else
|
||||
current_show_transitions.Add(from.Parent, new List<FSMTransitionData>() { item});
|
||||
}
|
||||
}
|
||||
|
||||
if(current_show_transitions.ContainsKey(parent))
|
||||
return current_show_transitions[parent];
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
public void Save() {
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
//UnityEditor.AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RefreshStateScripts()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
foreach (var state in states)
|
||||
{
|
||||
state.RefreshStateScripts(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void RefreshAllStateScripts()
|
||||
{
|
||||
string[] controllers = AssetDatabase.FindAssets("t:RuntimeFSMController");
|
||||
foreach (var item in controllers)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(item);
|
||||
RuntimeFSMController controller = AssetDatabase.LoadAssetAtPath<RuntimeFSMController>(path);
|
||||
controller.RefreshStateScripts();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6fbd4d875fc9c244aa5a60af9e992ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,444 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2de5c4a2106a1974cb5a81ddd326e731
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Packages/com.xfkj.xffsm@357f537fea/Runtime/XFFSM.asmdef
Normal file
3
Packages/com.xfkj.xffsm@357f537fea/Runtime/XFFSM.asmdef
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "XFFSM"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a07b959eaaa27134fb5c7a0b050f6401
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user