This commit is contained in:
2024-10-16 00:03:41 +08:00
commit 897058435c
5033 changed files with 1009728 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class FSMBoolConditionInspector : FSMConditionInspector
{
public override void OnGUI(Rect rect, FSMConditionData condition, RuntimeFSMController controller)
{
string text = condition.targetValue == 1 ? "True" : "False";
if (EditorGUI.DropdownButton(rect, new GUIContent(text), FocusType.Keyboard)) {
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("True"), condition.targetValue == 1, () => {
condition.targetValue = 1;
controller.Save();
});
//tempContent.text = "False";
menu.AddItem(new GUIContent("False"), condition.targetValue == 0, () => {
condition.targetValue = 0;
controller.Save();
});
menu.ShowAsContext();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ce9f38bc4f6646845b15aa6f152bb7a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
namespace XFFSM
{
public class FSMConditionInspector
{
public virtual void OnGUI(Rect rect, FSMConditionData condtion, RuntimeFSMController controller) {
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64ef6b93dc886854a899900b205641c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using System;
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class FSMFloatConditionInspector : FSMConditionInspector
{
private Rect leftRect;
private Rect rightRect;
//private GUIContent tempContent = new GUIContent();
public override void OnGUI(Rect rect, FSMConditionData condition, RuntimeFSMController controller)
{
leftRect.Set(rect.x, rect.y, rect.width / 2, rect.height);
rightRect.Set(rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height);
//tempContent.text = condition.compareType.ToString();
if (EditorGUI.DropdownButton(leftRect, new GUIContent(condition.compareType.ToString()), FocusType.Keyboard)) {
GenericMenu menu = new GenericMenu();
for (int i = 0; i < Enum.GetValues(typeof(CompareType)).Length; i++)
{
CompareType v = (CompareType)Enum.GetValues(typeof(CompareType)).GetValue(i);
if (v == CompareType.Equal || v == CompareType.NotEqual) continue;
menu.AddItem(new GUIContent(v.ToString()), condition.compareType == v, () => {
condition.compareType = v;
controller.Save();
});
}
menu.ShowAsContext();
}
condition.targetValue = EditorGUI.FloatField(rightRect, condition.targetValue);
EditorUtility.SetDirty(controller);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0769ca1535aa530498501eeea743587f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using System;
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class FSMIntConditionInspector : FSMConditionInspector
{
private Rect leftRect;
private Rect rightRect;
//private GUIContent tempContent = new GUIContent();
public override void OnGUI(Rect rect, FSMConditionData condition, RuntimeFSMController controller)
{
leftRect.Set(rect.x, rect.y, rect.width / 2, rect.height);
rightRect.Set(rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height);
//tempContent.text = condition.compareType.ToString();
if (EditorGUI.DropdownButton(leftRect, new GUIContent(condition.compareType.ToString()), FocusType.Keyboard))
{
GenericMenu menu = new GenericMenu();
for (int i = 0; i < Enum.GetValues(typeof(CompareType)).Length; i++)
{
CompareType v = (CompareType)Enum.GetValues(typeof(CompareType)).GetValue(i);
//if (v == CompareType.Equal || v == CompareType.NotEqual) continue;
//tempContent.text = v.ToString();
menu.AddItem(new GUIContent(v.ToString()), condition.compareType == v, () => {
condition.compareType = v;
controller.Save();
});
}
menu.ShowAsContext();
}
condition.targetValue = EditorGUI.IntField(rightRect, (int)condition.targetValue);
EditorUtility.SetDirty(controller);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a227da536ccef04d96788e51bad55fc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,266 @@
using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace XFFSM
{
[CustomEditor(typeof(FSMStateInspectorHelper))]
public class FSMStateInspector : Editor
{
//private string stateName;
private ReorderableList reorderableList;
private Rect popupRect;
private GUIContent btn_add_state_script = new GUIContent("Add State Script");
private GUIStyle ProjectBrowserHeaderBgMiddle = null;
private GUIStyle DD_HeaderStyle = null;
private GUIStyle PrefixLabel = null;
private GUIContent script_gui_content = new GUIContent();
private Vector2 scroll;
private void OnEnable()
{
FSMStateInspectorHelper helper = target as FSMStateInspectorHelper;
if (helper == null) { return; }
//reorderableList = new ReorderableList(helper.node.StateScripts, typeof(FSMStateScriptInfo), true, true, true, true);
//reorderableList.drawHeaderCallback += OnDrawHeaderCallback;
//reorderableList.onAddCallback += this.OnAddCallback;
//reorderableList.onRemoveCallback += this.OnRemoveCallback;
//reorderableList.drawElementCallback += this.DrawItem;
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
if (ProjectBrowserHeaderBgMiddle == null)
ProjectBrowserHeaderBgMiddle = new GUIStyle("AC BoldHeader");
if (DD_HeaderStyle == null)
{
DD_HeaderStyle = new GUIStyle("IconButton");
}
if (PrefixLabel == null)
{
PrefixLabel = new GUIStyle("PrefixLabel");
PrefixLabel.richText = true;
}
FSMStateInspectorHelper helper = target as FSMStateInspectorHelper;
if (helper == null) return;
bool disabled = EditorApplication.isPlaying || helper.node.IsAnyState || helper.node.IsEntryState || helper.node.IsUpState;
EditorGUI.BeginDisabledGroup(disabled);
//GUILayout.Space(-10);
//scroll = GUILayout.BeginScrollView(scroll);
Vector2 mousePosition = Event.current.mousePosition;
foreach (var item in helper.node.StateScripts)
{
// 刷新一下
if (string.IsNullOrEmpty(item.guid) && !string.IsNullOrEmpty(item.className))
helper.node.RefreshStateScripts(helper.controller);
// 根据guid加载到脚本信息
string path = AssetDatabase.GUIDToAssetPath(item.guid);
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
if (script == null) continue;
Type type = script.GetClass();
if (type == null) continue;
var r = EditorGUILayout.BeginHorizontal(GUILayout.Height(25));
r.x = 0;
r.width += 30;
GUI.Box(r, string.Empty, ProjectBrowserHeaderBgMiddle);
GUILayout.Space(-10);
GUILayout.Label(EditorGUIUtility.IconContent("d_cs Script Icon"), GUILayout.Width(20), GUILayout.Height(20));
string displayName = string.Empty;
if (type.IsSubclassOf(typeof(FSMState)))
{
displayName = type.Name;
script_gui_content.tooltip = string.Empty;
}
else
{
displayName = string.Format("{0}<color=yellow>(Script Missing)</color>", type.Name);
script_gui_content.tooltip = "脚本丢失,请检查该脚本是否继承自FSMState!";
}
script_gui_content.text = displayName;
GUILayout.Label(script_gui_content, PrefixLabel, GUILayout.Height(20));
GUILayout.FlexibleSpace();
GUILayout.BeginVertical();
GUILayout.Space(5);
if ( GUILayout.Button(EditorGUIUtility.IconContent("d__Menu"), DD_HeaderStyle, GUILayout.Width(25), GUILayout.Height(25)))
{
ShowMenu(script);
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
if ( Event.current.type == EventType.MouseUp && Event.current.button == 1 && r.Contains(mousePosition))
{
ShowMenu(script);
Event.current.Use();
}
if ( Event.current.type == EventType.MouseUp && Event.current.button == 0 && r.Contains(mousePosition)) {
EditorGUIUtility.PingObject(script);
Event.current.Use();
}
}
GUILayout.Space(30);
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(btn_add_state_script, GUILayout.Width(260), GUILayout.Height(25)))
{
popupRect.height = 300;
popupRect.y -= popupRect.height;
if (popupRect.y > 300)
popupRect.y -= popupRect.height + 25;
PopupWindow.Show(popupRect, new FSMSelectStateWindow(popupRect, helper.controller, helper.node));
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
var rect = GUILayoutUtility.GetRect(255, 0);
if (rect.width > 10)
popupRect = rect;
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
if(helper.controller != null)
helper.controller.Save();
//GUILayout.EndScrollView();
EditorGUI.EndDisabledGroup();
}
protected override void OnHeaderGUI()
{
//base.OnHeaderGUI();
FSMStateInspectorHelper helper = target as FSMStateInspectorHelper;
if (helper == null) return;
string name = null;
EditorGUI.BeginChangeCheck();
{
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
GUILayout.Label(EditorGUIUtility.IconContent("icons/processed/unityeditor/animations/animatorstate icon.asset"), GUILayout.Width(30), GUILayout.Height(30));
EditorGUILayout.LabelField("Name:", GUILayout.Width(60));
bool disabled = EditorApplication.isPlaying
|| helper.node.IsAnyState || helper.node.IsEntryState || helper.node.IsUpState;
EditorGUI.BeginDisabledGroup(disabled);
name = EditorGUILayout.DelayedTextField(helper.node.DisplayName);
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
}
if (EditorGUI.EndChangeCheck())
{
string oldName = helper.node.name;
bool success = FSMStateNodeFactory.Rename(helper.controller, helper.node, name);
if (success)
helper.grap.RenameState(oldName, name);
}
EditorGUILayout.Space();
var rect = EditorGUILayout.BeginHorizontal();
Handles.color = Color.black;
Handles.DrawLine(new Vector2(rect.x, rect.y), new Vector3(rect.x + rect.width, rect.y));
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
}
private void ShowMenu(MonoScript script)
{
FSMStateInspectorHelper helper = target as FSMStateInspectorHelper;
if (helper == null) return;
var genricMenu = new GenericMenu();
genricMenu.AddItem(new GUIContent("Remove Script"), false, () =>
{
helper.node.RemoveStateScript(script);
helper.controller.Save();
});
genricMenu.AddItem(new GUIContent("Edit Script"), false, () =>
{
AssetDatabase.OpenAsset(script);
});
genricMenu.ShowAsContext();
}
//private void DrawItem(Rect rect, int index, bool isActive, bool isFocused)
//{
// if (index < 0 || index >= reorderableList.list.Count) return;
// FSMStateScriptInfo info = reorderableList.list[index] as FSMStateScriptInfo;
// if (info == null) return;
// info.className = GUI.TextField(rect, info.className);
// if (string.IsNullOrEmpty(info.className))
// {
// EditorGUI.BeginDisabledGroup(true);
// GUI.Label(rect, "请输入类的全名(含命名空间)!");
// EditorGUI.EndDisabledGroup();
// }
//}
//private void OnDrawHeaderCallback(Rect rect)
//{
// GUI.Label(rect, "State Scripts");
//}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2304151d2a6c07d429a8183e483319c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using UnityEditor;
namespace XFFSM
{
public class FSMStateInspectorHelper : ScriptableObjectSingleton<FSMStateInspectorHelper>
{
//private static FSMStateInspectorHelper _instance;
//public static FSMStateInspectorHelper Instance {
// get {
// if (_instance == null) {
// _instance = ScriptableObject.CreateInstance<FSMStateInspectorHelper>();
// }
// return _instance;
// }
//}
public FSMStateNodeData node;
public RuntimeFSMController controller;
public FSMStateGraphView grap;
public void Inspect(RuntimeFSMController controller, FSMStateNodeData node, FSMStateGraphView grap) {
if (node == null)
{
Selection.activeObject = null;
return;
}
this.node = node;
this.controller = controller;
this.grap = grap;
Selection.activeObject = this;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9bff4756b18720a4c92ff5f539a260f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,304 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace XFFSM
{
[CustomEditor(typeof(FSMTransitionInspectorHelper))]
public class FSMTransitionInspector : Editor
{
private ReorderableList reorderableList;
private Rect condition_left_rect;
private Rect condition_right_rect;
private Rect popRect;
private GUIContent add_a_sets_of_conditions = null;
private GUIContent auto_switch = null;
private static Dictionary<ParameterType, FSMConditionInspector> conditionInspector = new Dictionary<ParameterType, FSMConditionInspector>();
private Dictionary<int, ReorderableList> reorderables = new Dictionary<int, ReorderableList>();
private bool autoSwitch;
private void OnEnable()
{
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
reorderableList = new ReorderableList(helper.transition.conditions, typeof(FSMConditionData), true, true, true, true);
reorderableList.drawHeaderCallback += OnDrawHeaderCallback;
reorderableList.onAddCallback += this.OnAddCallback;
reorderableList.onRemoveCallback += this.OnRemoveCallback;
reorderableList.drawElementCallback += this.DrawItem;
autoSwitch = helper.transition.AutoSwtich;
}
public override void OnInspectorGUI()
{
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying);
if (auto_switch == null)
auto_switch = new GUIContent("AutoSwitch", "当条件为空时,是否自动切换?当前过渡的条件为空时可用!");
EditorGUI.BeginDisabledGroup(!helper.transition.Empty);
Rect rect = GUILayoutUtility.GetRect(0f, 20, GUILayout.ExpandWidth(expand: true));
GUI.Label(rect, auto_switch);
rect.Set(rect.width - 20, rect.y, 20, 20);
if (helper.transition.Empty)
{
helper.transition.AutoSwtich = GUI.Toggle(rect, helper.transition.AutoSwtich, string.Empty);
}
else {
GUI.Toggle(rect,false, string.Empty);
}
if (autoSwitch != helper.transition.AutoSwtich)
{
helper.controller.Save();
autoSwitch = helper.transition.AutoSwtich;
}
GUILayout.Space(10);
EditorGUI.EndDisabledGroup();
reorderableList.list = helper.transition.conditions;
reorderableList.DoLayoutList();
GUILayout.Space(10);
for (int i = 0; i < helper.transition.group_conditions.Count; i++)
{
GroupCondition condition = helper.transition.group_conditions[i];
if (condition == null) continue;
ReorderableList list = GetReorderableList(condition);
if (list != null)
{
list.list = condition.conditions;
list.DoLayoutList();
GUILayout.Space(10);
}
}
if (add_a_sets_of_conditions == null)
add_a_sets_of_conditions = new GUIContent("Add a set of conditions","添加一组条件");
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (helper.transition.group_conditions.Count > 0)
{
GUILayout.Label("注:当有多组条件时,其中一组满足,状态就会切换!", "CN StatusWarn");
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(add_a_sets_of_conditions, GUILayout.Width(260), GUILayout.Height(25)))
{
helper.transition.group_conditions.Add(new GroupCondition());
helper.controller.Save();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
EditorGUI.EndDisabledGroup();
}
protected override void OnHeaderGUI()
{
//base.OnHeaderGUI();
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
GUILayout.BeginHorizontal();
GUILayout.Label(EditorGUIUtility.IconContent("icons/processed/unityeditor/animations/animatorstatetransition icon.asset"),GUILayout.Width(30),GUILayout.Height(30));
GUILayout.Label(string.Format("{0} -> {1}", helper.transition.fromStateName, helper.transition.toStateName));
GUILayout.EndHorizontal();
// 画一条 分隔的线
var rect = EditorGUILayout.BeginHorizontal();
Handles.color = Color.black;
Handles.DrawLine(new Vector2(rect.x, rect.y), new Vector3(rect.x + rect.width, rect.y));
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
}
private static void InitConditionInspectors() {
if (conditionInspector.Count == 0) {
conditionInspector.Add(ParameterType.Bool, new FSMBoolConditionInspector());
conditionInspector.Add(ParameterType.Float, new FSMFloatConditionInspector());
conditionInspector.Add(ParameterType.Int, new FSMIntConditionInspector());
conditionInspector.Add(ParameterType.Trigger, new FSMConditionInspector()); // 不需要做任何绘制
}
}
private void OnAddCallback(ReorderableList list) {
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
//Debug.Log("添加条件");
FSMConditionFactory.CreateCondition(helper.controller, helper.transition);
}
private void OnRemoveCallback(ReorderableList list)
{
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) return;
FSMConditionFactory.DeleteCondition(helper.controller, helper.transition,list.index);
}
private void DrawItem(Rect rect, int index, bool isActive, bool isFocused) {
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
var conditon = helper.transition.conditions[index];
DrawItemExcute(rect, conditon);
}
private void DrawItemExcute(Rect rect, FSMConditionData condition)
{
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) return;
condition_left_rect.Set(rect.x, rect.y, rect.width / 2, rect.height);
condition_right_rect.Set(rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height);
if (helper.controller.parameters.Count > 0)
{
//tempContent.text = conditon.parameterName;
if (EditorGUI.DropdownButton(condition_left_rect, new GUIContent(condition.parameterName), FocusType.Keyboard))
{
// 弹出选择参数的弹框 TODO
popRect.Set(rect.x, rect.y + 2, rect.width / 2, rect.height);
PopupWindow.Show(popRect, new FSMSelectParamWindow(rect.width / 2, condition, helper.controller));
}
}
InitConditionInspectors();
FSMParameterData parameter = helper.controller.GetParameterData(condition.parameterName);
if (parameter == null)
{
EditorGUI.LabelField(condition_right_rect, "缺少参数!");
}
else
{
// 根据不同的参数类型绘制不同的内容
if (conditionInspector.ContainsKey(parameter.parameterType))
// 进行绘制
if (conditionInspector[parameter.parameterType] != null)
conditionInspector[parameter.parameterType].OnGUI(condition_right_rect, condition, helper.controller);
else
Debug.LogErrorFormat("未查询到对应的绘制方式:{0}", parameter.parameterType);
}
}
private void OnDrawHeaderCallback(Rect rect)
{
GUI.Label(rect, "Conditions");
}
public ReorderableList GetReorderableList(GroupCondition condition)
{
if (condition == null)
return null;
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null)
return null;
int key = condition.GetHashCode();
if (!reorderables.ContainsKey(key))
{
ReorderableList list = new ReorderableList(condition.conditions, typeof(FSMConditionData), true, true, true, true);
list.drawHeaderCallback += (rect)=> {
GUI.Label(rect, "Conditions");
rect.Set(rect.width - 10, rect.y + 1, 25, 25);
if (GUI.Button(rect,EditorGUIUtility.IconContent("d__Menu"), "IconButton"))
{
ShowConditionMenu(condition);
}
};
list.onAddCallback += (a) => {
FSMConditionData data = FSMConditionFactory.CreateCondition(helper.controller);
condition.conditions.Add(data);
helper.controller.Save();
};
list.onRemoveCallback += (a) =>
{
if(a.index >= 0 && a.index < condition.conditions.Count)
condition.conditions.RemoveAt(a.index);
helper.controller.Save();
};
list.drawElementCallback += (rect,index,c,d) =>
{
DrawItemExcute(rect, condition.conditions[index]);
};
reorderables.Add(key, list);
}
return reorderables[key];
}
private void ShowConditionMenu(GroupCondition condition)
{
FSMTransitionInspectorHelper helper = target as FSMTransitionInspectorHelper;
if (helper == null) { return; }
var genricMenu = new GenericMenu();
genricMenu.AddItem(new GUIContent("Remove"), false, () =>
{
// 移除一组条件
helper.transition.group_conditions.Remove(condition);
helper.controller.Save();
});
genricMenu.ShowAsContext();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35e608d082dfb634986b77bdcb9a59cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEditor;
namespace XFFSM
{
public class FSMTransitionInspectorHelper : ScriptableObjectSingleton<FSMTransitionInspectorHelper>
{
public FSMTransitionData transition;
public RuntimeFSMController controller;
public void Inspect(RuntimeFSMController controller, FSMTransitionData transition)
{
if (transition == null)
{
Selection.activeObject = null;
return;
}
this.transition = transition;
this.controller = controller;
Selection.activeObject = this;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d83e4df9515f6834289221614fd2fd62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEngine;
namespace XFFSM
{
public class ScriptableObjectSingleton<T> : ScriptableObject where T : ScriptableObjectSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = CreateInstance<T>();
}
return _instance;
}
}
private void OnDisable()
{
_instance = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f161a7ba0c72a7249971e4d18ab4a249
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: