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,259 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class Context
{
#region
private RuntimeFSMController _runtimeFSMController;
public List<FSMStateNodeData> SelectNodes = new List<FSMStateNodeData>();
public FSMTransitionData selectTransition;
public bool isPreviewTransition = false;
public FSMStateNodeData fromState = null;
public FSMStateNodeData hoverState = null;
private FSMController _FSMController;
//private LayoutMatrix4x4Info _matrixInfo;
private static Context _instance;
//private List<FSMStateNodeData> current_show_state_node_data = new List<FSMStateNodeData>();
//private List<FSMTransitionData> current_show_transition_data = new List<FSMTransitionData>();
#endregion
#region Layers
private List<string> empty_layers = new List<string>();
public List<string> Layers
{
get {
if(RuntimeFSMController != null)
return RuntimeFSMController.Layers;
return empty_layers;
}
}
public string LayerParent
{
get
{
if (Layers.Count == 0)
return string.Empty;
return Layers[Layers.Count - 1];
}
}
public void AddLayer(string layer)
{
if (RuntimeFSMController == null) return;
RuntimeFSMController.AddLayer(layer);
}
public void RemoveLayer(int index, int count)
{
if (RuntimeFSMController == null) return;
RuntimeFSMController.RemoveLayer(index,count);
}
public void RemoveLast(string name)
{
if (RuntimeFSMController == null) return;
int index = RuntimeFSMController.Layers.Count - 1;
if (index >= 0 && index < RuntimeFSMController.Layers.Count)
{
string last = RuntimeFSMController.Layers[index];
if (!last.Equals(name))
return;
RuntimeFSMController.RemoveLayer(RuntimeFSMController.Layers.Count - 1, 1);
}
}
#endregion
#region
// 这个逻辑修改为如果只有一个,逻辑不变,
// 如果有多个,判断当前显示的是不是在多个中,如果在不做处理,如果不在设置为第一个
public RuntimeFSMController RuntimeFSMController {
get
{
if ( RuntimeFSMControllers != null && RuntimeFSMControllers.Count != 0)
{
if (FSMControllerIndex < 0 || FSMControllerIndex >= RuntimeFSMControllers.Count)
FSMControllerIndex = 0;
RuntimeFSMController controller = RuntimeFSMControllers[FSMControllerIndex];
if (controller != null && !string.IsNullOrEmpty(controller.originGUID) && _runtimeFSMControllerGUID != controller.originGUID)
{
PlayerPrefs.SetString("XFFSMRuntimeFSMControllerGUID", controller.originGUID);
_runtimeFSMControllerGUID = controller.originGUID;
//Debug.LogFormat("保存的GUID:{0}", _runtimeFSMControllerGUID);
}
return controller;
}
if (_runtimeFSMController == null)
{
string path = AssetDatabase.GUIDToAssetPath(RuntimeFSMControllerGUID);
_runtimeFSMController = AssetDatabase.LoadAssetAtPath<RuntimeFSMController>(path);
}
return _runtimeFSMController;
}
internal set
{
if (_runtimeFSMController == value) return;
_runtimeFSMController = value;
}
}
public FSMController FSMController {
get {
if (_FSMController == null)
{
GameObject gameObj = EditorUtility.InstanceIDToObject(FSMControllerInstanceID) as GameObject;
if (gameObj == null) return null;
_FSMController = gameObj.GetComponent<FSMController>();
}
return _FSMController;
}
}
private List<RuntimeFSMController> currentFSMControllers = new List<RuntimeFSMController> ();
public List<RuntimeFSMController> RuntimeFSMControllers
{
get
{
if (FSMController != null)
return FSMController.RuntimeFSMController;
currentFSMControllers.Clear();
if (_runtimeFSMController == null)
{
string path = AssetDatabase.GUIDToAssetPath(RuntimeFSMControllerGUID);
_runtimeFSMController = AssetDatabase.LoadAssetAtPath<RuntimeFSMController>(path);
}
if (_runtimeFSMController != null)
currentFSMControllers.Add(_runtimeFSMController);
return currentFSMControllers;
}
}
public static Context Instance
{
get {
if(_instance == null)
_instance = new Context();
return _instance;
}
}
internal int FSMControllerInstanceID
{
get
{
return PlayerPrefs.GetInt("XFFSMControllerInstanceID",0);
}
set {
PlayerPrefs.SetInt("XFFSMControllerInstanceID", value);
Object obj = EditorUtility.InstanceIDToObject(value);
GameObject gameObj = obj as GameObject;
if (gameObj != null && gameObj.GetComponent<FSMController>() != null) {
_FSMController = gameObj.GetComponent<FSMController>();
}
else
_FSMController = null;
}
}
private string _runtimeFSMControllerGUID;
internal string RuntimeFSMControllerGUID
{
get
{
return PlayerPrefs.GetString("XFFSMRuntimeFSMControllerGUID",string.Empty);
}
set
{
//Debug.LogFormat("修改GUID:{0}",value);
PlayerPrefs.SetString("XFFSMRuntimeFSMControllerGUID", value);
string path = AssetDatabase.GUIDToAssetPath(value);
RuntimeFSMController = AssetDatabase.LoadAssetAtPath<RuntimeFSMController>(path);
}
}
internal int FSMControllerIndex
{
get {
return PlayerPrefs.GetInt("FSMControllerIndex", 0);
}
set
{
if (FSMControllerIndex == value) return;
PlayerPrefs.SetInt("FSMControllerIndex", value);
}
}
#endregion
#region
private Context() {
}
public void ClearSelections()
{
// 如果不是 InspectorWindow 此时清空 Inspector
this.SelectNodes.Clear();
selectTransition = null;
Selection.activeObject = null;
//Selection.activeObject = this.RuntimeFSMController;
}
/// <summary>
/// 获取当前显示状态节点
/// </summary>
/// <returns></returns>
public List<FSMStateNodeData> GetCurrentShowStateNodeData() {
if (RuntimeFSMController != null)
return RuntimeFSMController.GetCurrentShowStateNodeData(LayerParent);
return null;
}
public List<FSMTransitionData> GetCurrentShowTransitionData()
{
if (RuntimeFSMController != null)
return RuntimeFSMController.GetCurrentShowTransitionData(LayerParent);
return null;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c7fdc94ab675d543b15b12578676825
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f1e1e098fe279240872b9a9e6cf099c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class GraphLayer
{
#region
protected Rect position;
#endregion
#region
public EditorWindow EditorWindow { get; private set; }
#endregion
#region
public GraphLayer(EditorWindow editorWindow) {
this.EditorWindow = editorWindow;
}
public virtual void OnGUI(Rect rect) {
position = rect;
UpdateTransformationMatrix();
}
public virtual void ProcessEvents() {
}
public virtual void Update() { }
private void UpdateTransformationMatrix()
{
//this.transormMatrix = Matrix4x4.TRS(position.center + this.Context.DragOffset , Quaternion.identity,Vector3.one * this.Context.ZoomFactor);
}
public virtual void OnLostFocus()
{
if (UnityEditor.EditorWindow.mouseOverWindow != null && UnityEditor.EditorWindow.mouseOverWindow.GetType().ToString().Equals("UnityEditor.InspectorWindow"))
return;
Context.Instance.ClearSelections();
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,350 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace XFFSM
{
public class ParamLayer : GraphLayer
{
#region
private ReorderableList reorderableList;
private ReorderableList reorderableListStates;
private Vector2 scrollView;
// 参数区域
//private Rect paramLabelRect;
//private Rect paramValueRect;
//const float param_value_width = 50f;
//const float param_value_padding = 2f;
private bool isRenaming = false;
private string newName;
private List<FSMParameterData> EmptyList = new List<FSMParameterData>();
private Rect headerRect = new Rect();
private string[] toolbars = new string[] { "Controllers", "Paramters" };
private int select = 1;
private int index = 0;
//private Vector3[] lines = new Vector3[2];
#endregion
#region
public override void OnGUI(Rect rect)
{
rect.Set(rect.x + 2,rect.y,rect.width,rect.height);
base.OnGUI(rect);
headerRect.Set(rect.x, rect.y, rect.width, 20);
//EditorGUI.DrawRect(headerRect, ColorConst.ParaBackground);
headerRect.Set(headerRect.x + 5, headerRect.y, 150, headerRect.height);
select = GUI.Toolbar(headerRect, select, toolbars, "toolbarbuttonLeft");
//Handles.color = Color.black;
//Handles.DrawLine(new Vector2(rect.x, rect.y + headerRect.height), new Vector2(rect.x + rect.width, rect.y + headerRect.height));
//Handles.DrawLine(new Vector2(rect.x + rect.width, rect.y), new Vector2(rect.x + rect.width, rect.y + rect.height));
// 偏移20, 用来绘制 States 和 Parmaters
rect.Set(rect.x, rect.y + 20, rect.width, rect.height);
//EditorGUI.DrawRect(rect, ColorConst.ParaBackground);
//GUI.Box(rect, string.Empty, GUI.skin.GetStyle("CN Box"));
if (select == 1)
{
DrawParamters(rect);
}
else {
DrawStates(rect);
}
}
private void DrawParamters(Rect rect)
{
if (reorderableList == null)
{
if (Context.Instance.RuntimeFSMController != null)
{
reorderableList = new ReorderableList(Context.Instance.RuntimeFSMController.parameters, typeof(FSMParameterData), true, true, true, true);
}
else
{
reorderableList = new ReorderableList(EmptyList, typeof(FSMParameterData), true, true, true, true);
}
reorderableList.drawHeaderCallback += HeaderCallbackDelegate;
reorderableList.onAddDropdownCallback += OnAddDropdownCallback;
reorderableList.onRemoveCallback += OnRemoveCallback;
reorderableList.drawElementCallback += DrawElementCallback;
reorderableList.onCanRemoveCallback += onCanRemoveCallback;
reorderableList.onCanAddCallback += onCanRemoveCallback;
}
if (Context.Instance.RuntimeFSMController != null)
reorderableList.list = Context.Instance.RuntimeFSMController.parameters;
else
reorderableList.list = EmptyList;
EditorGUI.BeginDisabledGroup(Context.Instance.RuntimeFSMController == null);
GUILayout.BeginArea(rect);
scrollView = GUILayout.BeginScrollView(scrollView);
reorderableList.DoLayoutList();
GUILayout.EndScrollView();
GUILayout.EndArea();
EditorGUI.EndDisabledGroup();
}
private void DrawStates(Rect rect)
{
if (reorderableListStates == null)
{
reorderableListStates = new ReorderableList(Context.Instance.RuntimeFSMControllers, typeof(RuntimeFSMController), false, true, false, false);
reorderableListStates.headerHeight = 0;
reorderableListStates.drawElementCallback += DrawStateElementCallback;
reorderableListStates.onSelectCallback += OnStateChanged;
}
for (int i = 0; i < Context.Instance.RuntimeFSMControllers.Count; i++)
{
if (Context.Instance.RuntimeFSMControllers[i] == null) {
Context.Instance.RuntimeFSMControllers.RemoveAt(i);
i--;
}
}
reorderableListStates.list = Context.Instance.RuntimeFSMControllers;
GUILayout.BeginArea(rect);
scrollView = GUILayout.BeginScrollView(scrollView);
reorderableListStates.DoLayoutList();
GUILayout.EndScrollView();
GUILayout.EndArea();
}
public override void ProcessEvents()
{
base.ProcessEvents();
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 &&
position.Contains(Event.current.mousePosition)
)
{
Context.Instance.ClearSelections();
}
}
public override void OnLostFocus()
{
base.OnLostFocus();
isRenaming = false;
}
#endregion
#region
public ParamLayer(EditorWindow editorWindow) : base(editorWindow)
{
}
// 添加
private void OnAddDropdownCallback(Rect buttonRect, ReorderableList list)
{
GenericMenu menu = new GenericMenu();
for (int i = 0; i < Enum.GetValues(typeof(ParameterType)).Length; i++)
{
ParameterType v = (ParameterType)Enum.GetValues(typeof(ParameterType)).GetValue(i);
menu.AddItem(new GUIContent(v.ToString()), false, () =>
{
FSMParamterFactory.CreateParamter(Context.Instance.RuntimeFSMController, v);
});
}
menu.ShowAsContext();
}
// 移除
private void OnRemoveCallback(ReorderableList list)
{
FSMParamterFactory.RemoveParamter(Context.Instance.RuntimeFSMController, list.index);
}
// 绘制每一条数据
private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
if (Context.Instance.RuntimeFSMController == null) return;
if (index < 0 || index >= Context.Instance.RuntimeFSMController.parameters.Count) return;
FSMParameterData parameter = Context.Instance.RuntimeFSMController.parameters[index];
if (parameter == null) return;
rect.width *= 0.6f;
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition) && isFocused )
{
isRenaming = true;
this.index = index;
}
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 &&
!rect.Contains(Event.current.mousePosition) && index == reorderableList.index)
{
EditorApplication.delayCall += () =>
{
isRenaming = false;
};
GUI.FocusControl(null);
}
// 按下回车键的时候 也需要取消重命名
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
{
EditorApplication.delayCall += () =>
{
isRenaming = false;
};
}
if (isRenaming && index == reorderableList.index)
{
// 绘制输入框
EditorGUI.BeginChangeCheck();
newName = EditorGUI.DelayedTextField(rect, parameter.name);
if (EditorGUI.EndChangeCheck() && this.index == index)
{
isRenaming = false;
if (parameter.name.Equals(newName)) return;
FSMParamterFactory.RenameParamter(Context.Instance.RuntimeFSMController, parameter, newName);
}
}
else
{
GUI.Label(rect, parameter.name);
}
rect.x += rect.width;
rect.width /= 3;
EditorGUI.BeginDisabledGroup(true);
GUI.Label(rect, GetParameterType(parameter));
EditorGUI.EndDisabledGroup();
rect.x += rect.width;
switch (parameter.parameterType)
{
case ParameterType.Float:
parameter.Value = EditorGUI.FloatField(rect, parameter.Value);
break;
case ParameterType.Int:
parameter.Value = EditorGUI.IntField(rect, (int)parameter.Value);
break;
case ParameterType.Bool:
parameter.Value = EditorGUI.Toggle(rect, parameter.Value == 1) ? 1 : 0;
break;
case ParameterType.Trigger:
parameter.Value = EditorGUI.Toggle(rect, parameter.Value == 1, GUI.skin.GetStyle("Radio")) ? 1 : 0;
break;
}
}
private string GetParameterType(FSMParameterData parameter)
{
switch (parameter.parameterType)
{
case ParameterType.Float:
return "Float";
case ParameterType.Int:
return "Int";
case ParameterType.Bool:
return "Bool";
case ParameterType.Trigger:
return "Trigger";
}
return string.Empty;
}
private void DrawStateElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
if (index < 0 || index >= Context.Instance.RuntimeFSMControllers.Count) return;
RuntimeFSMController controller = Context.Instance.RuntimeFSMControllers[index];
//if (controller == null) return;
try
{
GUIContent content = EditorGUIUtility.IconContent("AnimatorController Icon");
if (controller == Context.Instance.RuntimeFSMController)
GUI.Label(new Rect(rect.x, rect.y, rect.height, rect.height), "✓");
GUI.Label(new Rect(rect.x + rect.height, rect.y, rect.height, rect.height), content);
rect.Set(rect.x + rect.height * 2,rect.y,rect.width - rect.height,rect.height);
GUI.Label(rect,controller == null ? "None" : controller.name);
}
catch (Exception)
{
}
}
private bool onCanRemoveCallback(ReorderableList list)
{
return Application.isPlaying == false;
}
private void OnStateChanged(ReorderableList list)
{
if (Context.Instance.RuntimeFSMControllers == null || Context.Instance.RuntimeFSMControllers.Count == 0) return;
if (Context.Instance.RuntimeFSMController == Context.Instance.RuntimeFSMControllers[list.index]) return;
Context.Instance.FSMControllerIndex = list.index;
}
private void HeaderCallbackDelegate(Rect rect)
{
rect.width *= 0.6f;
rect.x += 15;
GUI.Label(rect,"名称");
rect.x += rect.width;
rect.width /= 3;
rect.x -= 10;
GUI.Label(rect, "类型");
rect.x += rect.width;
rect.x -= 5;
GUI.Label(rect, "值");
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e334cab2f8105f94a8bde697f6a370de
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
using UnityEditor;
using UnityEngine;
namespace XFFSM
{
public class PackageInfo
{
public string version;
}
public class FSMAboutWindow : EditorWindow
{
Rect textureRect = new Rect(0, 10, 291 * 0.7F, 96 * 0.7F);
Texture logo;
private GUIStyle style;
private string version;
private void Awake()
{
logo = AssetDatabase.LoadAssetAtPath<Texture>("Packages/com.xfkj.xffsm/Editor/Texture/logo_web.png");
TextAsset p = AssetDatabase.LoadAssetAtPath<TextAsset>("Packages/com.xfkj.xffsm/package.json");
if(p != null )
{
PackageInfo info = JsonUtility.FromJson<PackageInfo>(p.text);
version = string.Format("Version {0}", info.version);
}
}
private void ConfigStyle()
{
style = new GUIStyle(GUI.skin.label);
style.richText = true;
style.normal.textColor = new Color(0.03f, 0.4f, 0.9f, 1);
style.onHover.textColor = Color.white;
style.alignment = TextAnchor.MiddleLeft;
style.fontStyle = FontStyle.Italic;
//style.onFocused.textColor = Color.red;
}
// 每秒10帧更新
void OnInspectorUpdate()
{
//开启窗口的重绘,不然窗口信息不会刷新
Repaint();
}
private void OnGUI()
{
if(logo!=null)
GUI.DrawTexture(textureRect, logo);
GUILayout.Space(textureRect.height + 20);
GUILayout.BeginHorizontal();
GUILayout.Space(130);
GUILayout.Label(version);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("欢迎使用XFFSM!");
GUILayout.Label("XFFSM 是一款可视化有限状态机插件,XFFSM 能够帮助您加速开发流程,简化状态设计!");
GUILayout.Label("如果您在使用的过程碰到任何问题 或 错误请通过下面的QQ交流群联系到我们!");
GUILayout.Label("感谢您的支持!");
//GUILayout.Label("更多信息可通过点击下方教程链接获取!");
GUILayout.Space(20);
if (style == null)
{
ConfigStyle();
}
//DrawLink("更多教程:", "https://space.bilibili.com/258939476");
DrawLink("插件源码:", "https://gitee.com/xianfengkeji/xffsm");
GUILayout.Space(20);
GUILayout.Label("XFFSM 交流群:644685781");
//GUILayout.Space(20);
GUILayout.Label("*弦风课堂制作");
}
private void DrawLink(string title, string url)
{
GUILayout.BeginHorizontal();
GUILayout.Label(title, GUILayout.Width(60));
if (GUILayout.Button(url, style))
{
Application.OpenURL(url);
}
GUILayout.EndHorizontal();
}
}
}

View File

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

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace XFFSM
{
public class FSMParamListTree : TreeView
{
#region
private RuntimeFSMController controller;
private FSMConditionData condition;
#endregion
#region
protected override TreeViewItem BuildRoot()
{
TreeViewItem root = new TreeViewItem(-1, -1);
if (controller != null)
{
for (int i = 0; i < controller.parameters.Count; i++)
{
root.AddChild(new TreeViewItem(i, 0, controller.parameters[i].name));
}
}
return root;
}
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
{
return base.BuildRows(root);
}
protected override void SingleClickedItem(int id)
{
base.SingleClickedItem(id);
string paramterName = FindItem(id, rootItem).displayName;
FSMParameterData p = controller.GetParameterData(paramterName);
if (p != null)
{
condition.parameterName = paramterName;
switch (p.parameterType)
{
case ParameterType.Float:
case ParameterType.Int:
condition.compareType = CompareType.Greater;
break;
case ParameterType.Bool:
condition.compareType = CompareType.Equal;
break;
case ParameterType.Trigger:
condition.compareType = CompareType.Equal;
condition.targetValue = 1;
break;
}
}
else {
Debug.LogErrorFormat("参数查询失败:{0}", paramterName);
}
// 保存
controller.Save();
}
protected override void RowGUI(RowGUIArgs args)
{
base.RowGUI(args);
if ( args.label.Equals(condition.parameterName) ) {
GUI.Label(args.rowRect, "√");
}
}
#endregion
#region
public FSMParamListTree(TreeViewState state, RuntimeFSMController controller, FSMConditionData condition) : base(state)
{
this.controller = controller;
this.condition = condition;
showBorder = true;
showAlternatingRowBackgrounds = true;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,83 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace XFFSM
{
public class FSMSelectParamWindow : PopupWindowContent
{
#region
private float width;
private FSMConditionData condition;
private RuntimeFSMController controller;
// 搜索框
private SearchField searchField;
private Rect searchRect;
const float searchHeight = 25f;
// 标签
private Rect labelRect;
const float labelHeight = 30f;
// 参数列表
private FSMParamListTree paramTree;
private TreeViewState paramState;
private Rect paramRect;
#endregion
public FSMSelectParamWindow(float width,FSMConditionData condition,RuntimeFSMController controller)
{
this.width = width;
this.condition = condition;
this.controller = controller;
}
public override Vector2 GetWindowSize()
{
return new Vector2(this.width,120);
}
public override void OnGUI(Rect rect)
{
if (paramTree == null)
{
if (paramState == null)
{
paramState = new TreeViewState();
}
paramTree = new FSMParamListTree(paramState, controller, condition);
paramTree.Reload();
}
// 搜索框
if (searchField == null) {
searchField = new SearchField();
}
searchRect.Set(rect.x + 5, rect.y + 5, rect.width - 10, searchHeight);
paramTree.searchString = searchField.OnGUI(searchRect, paramTree.searchString);
// 标签
labelRect.Set(rect.x, rect.y + searchHeight, rect.width, labelHeight);
EditorGUI.LabelField(labelRect, condition.parameterName, GUI.skin.GetStyle("AC BoldHeader"));
// 参数列表
paramRect.Set(rect.x, rect.y + searchHeight + labelHeight - 5, rect.width, rect.height - searchHeight - labelHeight);
paramTree.OnGUI(paramRect);
}
}
}

View File

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

View File

@@ -0,0 +1,226 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace XFFSM
{
public class FSMSelectStateWindow : PopupWindowContent
{
// Fix编码
#region
private RuntimeFSMController controller;
// 搜索框
private SearchField searchField;
private Rect searchRect;
const float searchHeight = 25f;
// 标签
private Rect labelRect;
const float labelHeight = 30f;
// 参数列表
private FSMStateListTree stateTree;
private TreeViewState stateState;
private Rect stateRect;
private Rect rect;
private FSMStateNodeData nodeData;
private bool showCreateScriptGUI = false;
private string scriptName = string.Empty;
private string scriptName2;
#endregion
public FSMSelectStateWindow(Rect rect,RuntimeFSMController controller,FSMStateNodeData nodeData)
{
//this.width = width;
this.controller = controller;
this.rect = rect;
this.nodeData = nodeData;
this.showCreateScriptGUI = false;
EditorApplication.update -= Update;
EditorApplication.update += Update;
}
public override Vector2 GetWindowSize()
{
return new Vector2(this.rect.width, this.rect.height);
}
public override void OnGUI(Rect rect)
{
if (!showCreateScriptGUI)
{
OnGUISearchScripts(rect);
}
else {
OnGUICreateScripts(rect);
}
}
private void OnGUISearchScripts(Rect rect)
{
if (stateTree == null)
{
if (stateState == null)
{
stateState = new TreeViewState();
}
stateTree = new FSMStateListTree(stateState, controller, this.nodeData,editorWindow);
stateTree.Reload();
}
// 搜索框
if (searchField == null)
{
searchField = new SearchField();
}
searchRect.Set(rect.x + 5, rect.y + 5, rect.width - 5, searchHeight);
stateTree.searchString = searchField.OnGUI(searchRect, stateTree.searchString);
// 标签
labelRect.Set(rect.x, rect.y + searchHeight, rect.width, labelHeight);
EditorGUI.LabelField(labelRect, "FSMStates", GUI.skin.GetStyle("AC BoldHeader"));
// 参数列表
stateRect.Set(rect.x, rect.y + searchHeight + labelHeight - 5, rect.width, rect.height - searchHeight - labelHeight - 20);
stateTree.OnGUI(stateRect);
stateRect.Set(rect.x, stateRect.y + stateRect.height, rect.width, 23);
if (GUI.Button(stateRect, "New Scripts", "AppToolbarButtonMid")) {
showCreateScriptGUI = true;
scriptName = string.Empty;
}
}
private void OnGUICreateScripts(Rect rect) {
EditorGUI.BeginDisabledGroup(true);
// 搜索框
if (searchField == null)
{
searchField = new SearchField();
}
searchRect.Set(rect.x + 5, rect.y + 5, rect.width - 5, searchHeight);
stateTree.searchString = searchField.OnGUI(searchRect, stateTree.searchString);
EditorGUI.EndDisabledGroup();
// 标签
labelRect.Set(rect.x, rect.y + searchHeight, rect.width, labelHeight);
if (GUI.Button(labelRect, "New Script", "AC BoldHeader"))
{
showCreateScriptGUI = false;
}
labelRect.y -= 3;
GUI.Label(labelRect, EditorGUIUtility.IconContent("ArrowNavigationLeft"));
// 参数列表
stateRect.Set(rect.x, rect.y + searchHeight + labelHeight - 5, rect.width, rect.height - searchHeight - labelHeight - 20);
GUILayout.BeginArea(stateRect);
GUILayout.Space(10);
GUILayout.Label("Name");
EditorGUI.BeginChangeCheck();
scriptName2 = EditorGUILayout.DelayedTextField(scriptName);
if (EditorGUI.EndChangeCheck())
{
scriptName = scriptName2;
EditorApplication.delayCall += CreateAndAddScript;
}
//GUILayout.Label(string.Format("scriptName:{0} scriptName2:{1}", scriptName, scriptName2));
GUILayout.EndArea();
stateRect.Set(rect.x,rect.height - 23, rect.width, 23);
if (GUI.Button(stateRect, "Create And Add", "AppToolbarButtonMid"))
{
OnButtonClick();
}
if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return )
{
EditorApplication.delayCall += CreateAndAddScript;
}
}
private void Update() {
if(!showCreateScriptGUI && editorWindow != null)
editorWindow.Repaint();
if (EditorWindow.focusedWindow != editorWindow)
{
EditorApplication.update -= Update;
}
}
public void Close() {
EditorApplication.update -= Update;
if (editorWindow == null) {
Debug.Log("host view is null!");
return;
}
editorWindow.Close();
}
private void CreateAndAddScript() {
if (EditorWindow.focusedWindow != editorWindow)
return;
if (string.IsNullOrEmpty(scriptName2))
return;
FSMStateGraphView.SavePrefsSelection(this.nodeData.name);
string dir = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(controller));
string path = string.Format("{0}/{1}.cs", dir, scriptName2);
bool isSuccess = FSMStateCreator.CreateFSMState(path, false);
if (!isSuccess)
{
GUIContent content = new GUIContent(string.Format("名称:{0}不可用,请修改后重试!", scriptName));
this.editorWindow.ShowNotification(content);
return;
}
EditorApplication.delayCall += () =>
{
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
EditorGUIUtility.PingObject(script);
this.nodeData.AddStateScript(script);
controller.Save();
AssetDatabase.SaveAssets();
};
//Close();
}
private void OnButtonClick()
{
GUI.FocusControl(null);
}
}
}

View File

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

View File

@@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace XFFSM
{
public class FSMStateTreeViewItem : TreeViewItem
{
public MonoScript MonoScript { get; private set; }
private Type _type = null;
public Type Type
{
get
{
if (_type == null)
_type = MonoScript.GetClass();
return _type;
}
}
public FSMStateTreeViewItem(int id, int depth, string displayName, MonoScript script) : base(id, depth, displayName)
{
MonoScript = script;
}
}
public class FSMStateListTree : TreeView
{
// Fix编码
#region
private RuntimeFSMController controller;
//private FSMConditionData condition;
private GUIStyle style = new GUIStyle("label");
private FSMStateNodeData nodeData = null;
private EditorWindow editorWindow = null;
private List<int> selections = new List<int>();
#endregion
#region
protected override TreeViewItem BuildRoot()
{
TreeViewItem root = new TreeViewItem(-1, -1);
List<MonoScript> scripts = AssemblyTools.GetAllStatesType();
for (int i = 0; i < scripts.Count; i++)
{
Type type = scripts[i].GetClass();
if (type == null) continue;
string displayName = type.Name;
FSMStateTreeViewItem item = new FSMStateTreeViewItem(i, 0, displayName, scripts[i]);
root.AddChild(item);
}
return root;
}
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
{
return base.BuildRows(root);
}
protected override void SingleClickedItem(int id)
{
base.SingleClickedItem(id);
FSMStateTreeViewItem item = FindItem(id, rootItem) as FSMStateTreeViewItem;
if (item != null)
{
try
{
nodeData.AddStateScript(item.MonoScript);
}
catch (Exception e)
{
editorWindow.ShowNotification(new GUIContent(e.Message));
return;
}
}
// 保存
controller.Save();
editorWindow.Close();
}
protected override void RowGUI(RowGUIArgs args)
{
//base.RowGUI(args);
FSMStateTreeViewItem item = args.item as FSMStateTreeViewItem;
if (item == null) return;
Type type = item.Type;
if (type == null) return;
if (args.rowRect.Contains(Event.current.mousePosition))
{
selections.Clear();
selections.Add(item.id);
this.SetSelection(selections);
}
Rect rect = new Rect();
rect.Set(args.rowRect.x + 20,args.rowRect.y,args.rowRect.width - 20, args.rowRect.height);
GUI.Label(new Rect(0, args.rowRect.y - 2, 20, 20), EditorGUIUtility.IconContent("d_cs Script Icon"));
if (string.IsNullOrEmpty(type.Namespace)) {
GUI.Label(rect, type.Name);
}
else
{
style.richText = true;
GUI.Label(rect, string.Format("{0}<color=#A4A4A4>({1})</color>", type.Name, type.Namespace), style);
}
//EditorGUIUtility.IconContent("d_cs Script Icon");
}
//protected override void ContextClicked()
//{
// base.ContextClicked();
//}
protected override void SelectionChanged(IList<int> selectedIds)
{
base.SelectionChanged(selectedIds);
}
protected override bool CanMultiSelect(TreeViewItem item)
{
return false;
}
#endregion
#region
public FSMStateListTree(TreeViewState state, RuntimeFSMController controller, FSMStateNodeData nodeData,EditorWindow editorWindow) : base(state)
{
this.controller = controller;
showBorder = true;
showAlternatingRowBackgrounds = true;
this.nodeData = nodeData;
this.editorWindow = editorWindow;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 45e08d70a1e332e43a9f9cb144a75845
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,337 @@
using UnityEditor;
using UnityEditor.Graphs;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMEditorWindow : EditorWindow
{
#region
private static FSMEditorWindow _instance;
private float percent_of_param = 0.3f; // 参数所占用的比例
private VisualElement left = null;
private VisualElement middle = null;
private VisualElement right = null;
private Rect paramResizeArea;
const float ResizeWidth = 5;
private bool isResizingParamArea = false; // 是否正在调整参数区域
private Rect stateRect;
private FSMStateGraphView graphGUI = null;
private ParamLayer paramLayer = null;
private IMGUIContainer state_top_container;
private IMGUIContainer state_bottom_container;
private Vector3 splitLineStart;
private Vector3 splitLineEnd;
private string parentLayer;
#endregion
// Fix编码
private void Awake()
{
try
{
this.titleContent = new GUIContent("XFFSM", EditorGUIUtility.IconContent("AnimatorController Icon").image);
}
catch (System.Exception)
{
this.titleContent = new GUIContent("XFFSM");
}
}
private void InitGUI()
{
rootVisualElement.Clear();
ClearInspetor();
rootVisualElement.style.flexDirection = FlexDirection.Row;
left = new VisualElement();
IMGUIContainer param_container = new IMGUIContainer();
param_container.onGUIHandler += () =>
{
if (paramLayer == null)
{
paramLayer = new ParamLayer(this);
}
paramLayer.OnGUI(param_container.layout);
paramLayer.ProcessEvents();
};
param_container.StretchToParentSize();
left.Add(param_container);
middle = new VisualElement();
right = new VisualElement();
state_top_container = new IMGUIContainer();
state_top_container.onGUIHandler += () =>
{
DoGraphToolbar(state_top_container.layout);
};
right.Add(state_top_container);
graphGUI = new FSMStateGraphView();
//graphGUI.StretchToParentSize();
right.Add(graphGUI);
state_bottom_container = new IMGUIContainer();
state_bottom_container.onGUIHandler += () =>
{
DrawButtom(state_bottom_container.layout);
};
right.Add(state_bottom_container);
rootVisualElement.Add(left);
rootVisualElement.Add(middle);
rootVisualElement.Add(right);
middle.RegisterCallback<MouseDownEvent>((e) =>
{
if (e != null && e.button == 0)
{
isResizingParamArea = true;
}
});
rootVisualElement.RegisterCallback<MouseUpEvent>(OnMouseUpEvent);
}
private void ClearInspetor()
{
// 清空当前的Inspector
if (Selection.activeObject == null)
return;
if (Selection.activeObject.GetType() == typeof(FSMStateInspectorHelper) ||
Selection.activeObject.GetType() == typeof(FSMTransitionInspectorHelper))
{
Selection.activeObject = null;
}
}
private void Update()
{
Repaint();
if (graphGUI != null)
graphGUI.Update();
}
private void OnGUI()
{
wantsMouseEnterLeaveWindow = true;
wantsMouseMove = true;
stateRect.Set(this.position.width * percent_of_param + 2, 20, this.position.width * (1 - percent_of_param), position.height - 15);
if (Event.current.type == EventType.Repaint)
Styles.graphBackground.Draw(stateRect, isHover: false, isActive: false, on: false, hasKeyboardFocus: false);
if (left == null)
{
InitGUI();
}
ParamAreaResize();
left.style.width = this.position.width * percent_of_param - ResizeWidth / 2;
left.style.height = this.position.height;
middle.style.width = ResizeWidth;
middle.style.height = this.position.height;
right.style.width = this.position.width * (1 - percent_of_param) - ResizeWidth / 2;
right.style.height = this.position.height;
state_top_container.style.width = right.style.width;
state_top_container.style.height = 20;
graphGUI.style.width = right.style.width;
graphGUI.style.height = this.position.height - 35;
state_bottom_container.style.width = right.style.width;
state_bottom_container.style.height = 15;
splitLineStart.Set(this.position.width * percent_of_param + 2, 0, 0);
splitLineEnd.Set(this.position.width * percent_of_param + 2, this.position.height, 0);
Handles.color = Color.black;
Handles.DrawAAPolyLine(2, splitLineStart, splitLineEnd);
graphGUI.OnGUI();
// 取消拖拽
if (Event.current.type == EventType.MouseLeaveWindow && Event.current.button == 0)
{
isResizingParamArea = false;
}
_instance = this;
}
private void ParamAreaResize()
{
paramResizeArea.Set(this.position.width * percent_of_param - ResizeWidth / 2, 0, ResizeWidth, position.height);
EditorGUIUtility.AddCursorRect(paramResizeArea, MouseCursor.ResizeHorizontal);
if (paramResizeArea.Contains(Event.current.mousePosition))
{
Vector3 start = paramResizeArea.center - new Vector2(-1, paramResizeArea.height / 2);
Vector3 end = paramResizeArea.center + new Vector2(1, paramResizeArea.height / 2);
Handles.color = isResizingParamArea ? Color.green : Color.white;
Handles.DrawLine(start, end);
}
if (isResizingParamArea)
{
percent_of_param = Mathf.Clamp(Event.current.mousePosition.x / position.width, 0.1f, 0.5f);
if (this.position.width * percent_of_param < 150)
percent_of_param = 150 / this.position.width;
}
}
private void DoGraphToolbar(Rect toolbarRect)
{
Handles.color = new Color(0, 0, 0, 0.4f);
Handles.DrawLine(new Vector3(toolbarRect.x, 0), new Vector3(toolbarRect.x + toolbarRect.width, 0));
GUILayout.BeginArea(toolbarRect);
GUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUI.BeginChangeCheck();
BreadCrumb(0, Context.Instance.Layers.Count + 1, "Base Layer");
if (EditorGUI.EndChangeCheck() && Context.Instance.Layers.Count > 0)
{
Context.Instance.RemoveLayer(0, Context.Instance.Layers.Count);
}
for (int i = 0; i < Context.Instance.Layers.Count; i++)
{
EditorGUI.BeginChangeCheck();
BreadCrumb(i + 1, Context.Instance.Layers.Count + 1, Context.Instance.Layers[i]);
if (EditorGUI.EndChangeCheck())
{
Context.Instance.RemoveLayer(i + 1, Context.Instance.Layers.Count - 1 - i);
}
}
if (parentLayer != Context.Instance.LayerParent && graphGUI != null)
{
graphGUI.RefreshNodes();
parentLayer = Context.Instance.LayerParent;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
private static Rect GetBreadcrumbLayoutRect(GUIContent content, GUIStyle style)
{
Texture image = content.image;
content.image = null;
Vector2 vector = style.CalcSize(content);
content.image = image;
if (image != null)
{
vector.x += vector.y;
}
return GUILayoutUtility.GetRect(content, style, GUILayout.MaxWidth(vector.x));
}
private void BreadCrumb(int index, int maxCount, string name)
{
GUIStyle style = index == 0 ? "GUIEditor.BreadcrumbLeft" : "GUIEditor.BreadcrumbMid";
GUIStyle gUIStyle = ((index == 0) ? "GUIEditor.BreadcrumbLeftBackground" : "GUIEditor.BreadcrumbMidBackground");
GUIContent content = new GUIContent(name);
Rect breadcrumbLayoutRect = GetBreadcrumbLayoutRect(content, style);
if (Event.current.type == EventType.Repaint)
{
gUIStyle.Draw(breadcrumbLayoutRect, GUIContent.none, 0);
}
GUI.Toggle(breadcrumbLayoutRect, index == maxCount - 1, content, style);
}
private void DrawButtom(Rect rect)
{
rect.Set(0, 0, rect.width, rect.height);
GUILayout.BeginArea(rect);
GUILayout.BeginHorizontal();
if (Context.Instance.FSMController != null)
{
if (GUILayout.Button(Context.Instance.FSMController.name, "ShurikenLabel"))
EditorGUIUtility.PingObject(Context.Instance.FSMController.gameObject);
}
GUILayout.FlexibleSpace();
if (GUILayout.Button(AssetDatabase.GetAssetPath(Context.Instance.RuntimeFSMController), "ShurikenLabel"))
EditorGUIUtility.PingObject(Context.Instance.RuntimeFSMController);
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
private void OnMouseUpEvent(MouseUpEvent e)
{
if (e != null && e.button == 0)
{
isResizingParamArea = false;
}
if (graphGUI != null && e.button == 0 )
{
graphGUI.selector.CancelDrag();
}
}
private void OnDisable()
{
ClearInspetor();
_instance = null;
}
public static void ShowNotification(string message)
{
if (_instance == null)
return;
_instance.ShowNotification(new GUIContent(message));
}
}
}

View File

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

View File

@@ -0,0 +1,167 @@
using System;
using UnityEditor;
using UnityEditor.Graphs;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMGridBackground : ImmediateModeElement
{
private VisualElement m_Container;
private Vector3 point_left_top;
private Vector3 point_right_bottom;
private Rect renderRect;
private static readonly Color LineColorDark = new Color(0f, 0f, 0f, 0.45f);
private static readonly Color LineColorLight = new Color(0f, 0f, 0f, 0.15f);
private float gridSpace = 20;
private float scale = 1;
private static Color LineColor
{
get
{
if (EditorGUIUtility.isProSkin)
{
return LineColorDark;
}
return LineColorLight;
}
}
private Rect backgroundRect;
// Fix编码
protected override void ImmediateRepaint()
{
if (Event.current.type != EventType.Repaint)
return;
VisualElement visualElement = base.parent;
FSMStateGraphView graphView = visualElement as FSMStateGraphView;
if (graphView == null)
{
throw new InvalidOperationException("GridBackground can only be added to a GraphView");
}
backgroundRect.Set(0, 0, graphView.layout.width, graphView.layout.height);
Styles.graphBackground.Draw(backgroundRect, isHover: false, isActive: false, on: false, hasKeyboardFocus: false);
m_Container = graphView.contentViewContainer;
Matrix4x4 inverse = m_Container.transform.matrix.inverse;
Rect clipRect = graphView.layout;
//Debug.Log(clipRect.ToString());
point_left_top.Set(clipRect.xMin, 0, 0);
point_right_bottom.Set(clipRect.xMax, clipRect.yMax, 0);
point_left_top = inverse.MultiplyPoint(point_left_top);
point_right_bottom = inverse.MultiplyPoint(point_right_bottom);
float width = Mathf.Abs(point_right_bottom.x - point_left_top.x);
float height = Mathf.Abs(point_right_bottom.y - point_left_top.y);
renderRect.Set(point_left_top.x, point_left_top.y, width, height);
Color color = Color.white;
if (graphView.scale < scale)
{
color.a = Mathf.InverseLerp(scale * 0.1f, scale, graphView.scale);
}
else
{
color.a = Mathf.InverseLerp(scale * 10, scale, graphView.scale);
}
DrawGrid(gridSpace, LineColor * color, renderRect);
DrawGrid(gridSpace * 10, LineColor, renderRect);
//GUI.Label(new Rect(0, 0, 300, 100), graphView.scale.ToString());
UpdateSpace(graphView.scale);
}
public void DrawGrid(float gridSpacing, Color gridColor, Rect rect)
{
if (gridSpacing == 0) return;
if (Mathf.Abs(gridSpacing) > rect.width || Mathf.Abs(gridSpacing) > rect.height) return;
Vector2 point_start = new Vector2();
Vector2 point_end = new Vector2();
float offset_x = rect.x - (int)(rect.x / gridSpacing) * gridSpacing;
float offset_y = rect.y - (int)(rect.y / gridSpacing) * gridSpacing;
for (float i = rect.x - offset_x; i < rect.x + rect.width; i += gridSpacing)
{
point_start.Set(i, rect.y);
point_start = m_Container.transform.matrix.MultiplyPoint(point_start);
point_end.Set(i, rect.y + rect.height);
point_end = m_Container.transform.matrix.MultiplyPoint(point_end);
DrawLine(point_start, point_end, gridColor);
int x = (int)(i / gridSpacing);
}
for (float i = rect.y - offset_y; i < rect.y + rect.height; i += gridSpacing)
{
point_start.Set(rect.x, i);
point_start = m_Container.transform.matrix.MultiplyPoint(point_start);
point_end.Set(rect.x + rect.width, i);
point_end = m_Container.transform.matrix.MultiplyPoint(point_end);
DrawLine(point_start, point_end, gridColor);
int y = (int)(i / gridSpacing);
}
}
private static void DrawLine(Vector2 start, Vector2 end, Color lineColor)
{
Handles.color = lineColor;
Handles.DrawLine(start, end);
}
private void UpdateSpace(float currentScale)
{
if (currentScale / scale >= 2)
{
// 放大了10倍
gridSpace /= 10;
scale *= 10;
}
else if (currentScale / scale <= 0.2f)
{
// 缩小了10倍
gridSpace *= 10;
scale *= 0.1f;
}
}
}
}

View File

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

View File

@@ -0,0 +1,295 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMNodeView : Node
{
public FSMStateNodeData Data { get;private set; }
private FSMStateGraphView graphView = null;
private GUIStyle labelStyle = null;
private float runingTimer;
public FSMNodeView(FSMStateNodeData data, FSMStateGraphView graphView)
{
this.Data = data;
this.graphView = graphView;
Clear();
VisualElement image = new VisualElement();
image.style.width = 200;
image.style.height = 40;
IMGUIContainer container = new IMGUIContainer();
container.onGUIHandler += () =>
{
if (Context.Instance.RuntimeFSMController == null)
return;
if (labelStyle == null)
{
labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.alignment = TextAnchor.MiddleCenter;
labelStyle.fontSize = 15;
labelStyle.padding.top = -5;
}
GUI.Label(container.layout,string.Empty, GetStateStyle(selected));
GUI.Label(container.layout, Data.DisplayName, labelStyle);
DrawRuning(container.layout);
};
container.StretchToParentSize();
//image.name = "node-border";
image.style.borderRightWidth = 0;
image.style.borderLeftWidth = 0;
image.style.borderTopWidth = 0;
image.style.borderBottomWidth = 0;
image.Add(container);
Add(image);
RegisterCallback<MouseDownEvent>(OnMouseDownEvent);
}
public override void SetPosition(Rect newPos)
{
if (Vector2.Distance(newPos.position, GetPosition().position) < 10)
return;
// 实际位置
newPos.Set((int)(newPos.x / 20) * 20 , (int)(newPos.y / 20) * 20,FSMConst.StateNodeWith, FSMConst.StateNodeHeight);
// 显示位置
base.SetPosition(new Rect(newPos.x - 2,newPos.y - 2 ,newPos.width,newPos.height));
Data.rect = newPos;
if (Context.Instance.RuntimeFSMController != null)
Context.Instance.RuntimeFSMController.Save();
}
public void ShowMenu(ContextualMenuPopulateEvent evt)
{
bool is_any = Data.IsAnyState;
bool is_entry = Data.IsEntryState;
if (!is_entry && !Data.IsUpState)
{
evt.menu.AppendAction( "Make Transition",(a) =>
{
graphView.StartMakeTransition(this);
});
}
else
{
evt.menu.AppendAction( "Make Transition", null, DropdownMenuAction.Status.Disabled);
}
if (!is_entry && !is_any && !Data.IsUpState)
{
if (Data.defaultState)
{
evt.menu.AppendAction("Set as Layer Default State",null, DropdownMenuAction.Status.Disabled);
}
else
{
evt.menu.AppendAction( "Set as Layer Default State", (a) =>
{
//SetDefaultState(node);
SetDefaultState();
graphView.RefreshNodes();
});
}
evt.menu.AppendAction( "Delete",(a) =>
{
DeleteStates();
});
}
}
private void DeleteStates()
{
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
if (controller == null)
return;
foreach (var item in graphView.StateNodes.Values)
{
if (item.selected)
FSMStateNodeFactory.DeleteState(controller, item.Data);
}
graphView.RefreshNodes();
}
private void SetDefaultState()
{
List<FSMStateNodeData> states = Context.Instance.GetCurrentShowStateNodeData();
if (states != null)
{
foreach (var item in states)
{
item.defaultState = false;
}
}
this.Data.defaultState = true;
Context.Instance.RuntimeFSMController.Save();
}
private GUIStyle GetStateStyle(bool selected)
{
if(Data.defaultState)
{
if (Data.isSubStateMachine)
return StateStyles.Get(selected ? Style.OrangeOnHEX : Style.OrangeHEX);
return StateStyles.Get(selected ? Style.OrangeOn : Style.Orange);
}
else if (Data.IsEntryState)
{
if (Data.isSubStateMachine)
return StateStyles.Get(selected ? Style.GreenOnHEX : Style.GreenHEX);
return StateStyles.Get(selected ? Style.GreenOn : Style.Green);
}
else if (Data.IsAnyState)
{
if (Data.isSubStateMachine)
return StateStyles.Get(selected ? Style.MintOnHEX : Style.MintHEX);
return StateStyles.Get(selected ? Style.MintOn : Style.Mint);
}
else if (Data.IsUpState)
{
return StateStyles.Get(selected ? Style.RedOnHEX : Style.RedHEX);
}
else
{
if (Data.isSubStateMachine)
return StateStyles.Get(selected ? Style.NormalOnHEX : Style.NormalHEX);
return StateStyles.Get(selected ? Style.NormalOn : Style.Normal);
}
}
public override void OnSelected()
{
base.OnSelected();
EditorApplication.delayCall -= DelayCallSelection;
EditorApplication.delayCall += DelayCallSelection;
}
private void DelayCallSelection() {
FSMStateInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, Data, graphView);
}
public override void OnUnselected()
{
base.OnUnselected();
FSMStateInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, null, graphView);
}
private void DrawRuning(Rect rect)
{
FSMStateNode currentState = GetCurrentState();
if (currentState == null) return;
if (Event.current.type != EventType.Repaint || (!(currentState.data.name == Data.name)))
return;
rect.Set(15, 28, rect.width - 30, 20);
runingTimer += Time.unscaledDeltaTime;
if (runingTimer >= 1)
runingTimer = 0;
GUIStyle gUIStyle = "MeLivePlayBackground";
GUIStyle gUIStyle2 = "MeLivePlayBar";
rect = gUIStyle.margin.Remove(rect);
Rect rect2 = gUIStyle.padding.Remove(rect);
rect2.width *= runingTimer;
gUIStyle2.Draw(rect2, isHover: false, isActive: false, on: false, hasKeyboardFocus: false);
gUIStyle.Draw(rect, isHover: false, isActive: false, on: false, hasKeyboardFocus: false);
}
private FSMStateNode GetCurrentState()
{
if (!Application.isPlaying)
return null;
if (Context.Instance.FSMController == null) return null;
if (Context.Instance.FSMController.RuntimeFSMController == null) return null;
if (Context.Instance.RuntimeFSMController == null) return null;
// 如果在运行时 正在运行的状态是orange
int index = Context.Instance.FSMController.RuntimeFSMController.IndexOf(Context.Instance.RuntimeFSMController);
FSMStateNode current_state_node = Context.Instance.FSMController.GetCurrentStateInfo(index, Context.Instance.LayerParent);
return current_state_node;
}
public void OnMouseDownEvent(MouseDownEvent evt)
{
if (evt != null && evt.pressedButtons == 1 && evt.clickCount == 1)
{
if (graphView.isMakeTransition)
graphView.StopMakeTransition(this);
//graphView.selector.DragStateNodeStart();
DelayCallSelection();
}
if (evt != null && evt.pressedButtons == 1 && evt.clickCount == 2)
{
if (Data.isSubStateMachine)
{
Context.Instance.AddLayer(Data.name);
graphView.RefreshNodes();
}
if (Data.IsUpState)
{
Context.Instance.RemoveLast(Data.Parent);
graphView.RefreshNodes();
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using UnityEditor.Graphs;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMRectangleSelector : ImmediateModeElement
{
private Vector3 dragStartPoint;
public bool Dragging { get; private set; } = false;
private Vector3 currentMousePosition;
private VisualElement m_Container;
private FSMStateGraphView graphView;
// Fix编码
internal static Rect FromToRect(Vector2 start, Vector2 end)
{
Rect result = new Rect(start.x, start.y, end.x - start.x, end.y - start.y);
if (result.width < 0f)
{
result.x += result.width;
result.width = 0f - result.width;
}
if (result.height < 0f)
{
result.y += result.height;
result.height = 0f - result.height;
}
return result;
}
private Dictionary<string, Vector3> node_postion_offset = new Dictionary<string, Vector3>();
protected override void ImmediateRepaint()
{
VisualElement visualElement = base.parent;
graphView = visualElement as FSMStateGraphView;
if (graphView == null)
{
throw new InvalidOperationException("FSMRectangleSelector can only be added to a GraphView");
}
currentMousePosition = Event.current.mousePosition;
if (Event.current.type == EventType.Repaint && Dragging)
Styles.selectionRect.Draw(FromToRect(dragStartPoint, Event.current.mousePosition), isHover: false, isActive: false, on: false, hasKeyboardFocus: false);
m_Container = graphView.contentViewContainer;
Matrix4x4 inverse = m_Container.transform.matrix.inverse;
if (Dragging)
{
Vector3 start = inverse.MultiplyPoint(dragStartPoint);
Vector3 end = inverse.MultiplyPoint(currentMousePosition);
Rect dragRect = FromToRect(start, end);
graphView.graphElements.ForEach((e) =>
{
//Debug.LogFormat("name:{0} position:{1}", e.name, e.GetPosition());
if (dragRect.Overlaps(e.GetPosition()))
{
graphView.AddToSelection(e);
}
else {
graphView.RemoveFromSelection(e);
}
});
}
UpdateHoverState();
}
public void ExecuteAction(EventBase evt)
{
VisualElement visualElement = base.parent;
graphView = visualElement as FSMStateGraphView;
if (graphView == null)
{
throw new InvalidOperationException("FSMRectangleSelector can only be added to a GraphView");
}
MouseDownEvent mouseDownEvent = evt as MouseDownEvent;
if (mouseDownEvent != null && mouseDownEvent.button == 0 && graphView.HoverNode == null)
{
dragStartPoint = currentMousePosition;
Dragging = true;
}
MouseUpEvent mouseUpEvent = evt as MouseUpEvent;
if (mouseUpEvent != null && Event.current.button == 0)
{
Dragging = false;
}
MouseLeaveWindowEvent windowEvent = evt as MouseLeaveWindowEvent;
if (windowEvent != null && windowEvent.button == 0)
{
Dragging = false;
}
//DragStateNode(evt);
}
public void CancelDrag() {
Dragging = false;
}
private void UpdateHoverState()
{
if (graphView == null)
return;
m_Container = graphView.contentViewContainer;
Matrix4x4 inverse = m_Container.transform.matrix.inverse;
Vector3 point = inverse.MultiplyPoint(currentMousePosition);
bool isHover = false;
foreach (var item in graphView.StateNodes.Values)
{
if (item.GetPosition().Contains(point))
{
graphView.transition.CloseTransition = null;
graphView.HoverNode = item;
isHover = true;
break;
}
}
if (!isHover)
{
graphView.HoverNode = null;
}
}
//internal void DragStateNodeStart()
//{
// if (graphView == null)
// return;
// m_Container = graphView.contentViewContainer;
// Matrix4x4 inverse = m_Container.transform.matrix.inverse;
// Vector3 point = inverse.MultiplyPoint(currentMousePosition);
// node_postion_offset.Clear();
// foreach (var item in graphView.StateNodes.Keys)
// {
// FSMNodeView node = graphView.StateNodes[item];
// if (node == null) continue;
// node_postion_offset.Add(item, node.GetPosition().center - (Vector2)point);
// }
//}
//private void DragStateNode(EventBase evt)
//{
// if (graphView == null)
// return;
// m_Container = graphView.contentViewContainer;
// Matrix4x4 inverse = m_Container.transform.matrix.inverse;
// Vector3 point = inverse.MultiplyPoint(currentMousePosition);
// MouseMoveEvent mouseMoveEvent = evt as MouseMoveEvent;
// if (mouseMoveEvent != null && mouseMoveEvent.pressedButtons == 1)
// {
// //Debug.LogFormat("鼠标移动:{0} detal:{1}", mouseMoveEvent.pressedButtons, mouseMoveEvent.mouseDelta);
// foreach (var item in graphView.StateNodes.Keys)
// {
// FSMNodeView node = graphView.StateNodes[item];
// if(node == null) continue;
// if (!node.selected) continue;
// if(!node_postion_offset.ContainsKey(item)) continue;
// Debug.LogFormat("修改位置:{0}",item);
// Rect position = node.GetPosition();
// position.center = point + node_postion_offset[item];
// node.SetPosition(position);
// }
// }
//}
//internal void DragStateNodeEnd() {
// node_postion_offset.Clear();
//}
}
}

View File

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

View File

@@ -0,0 +1,544 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMSelectionDragger : Dragger
{
private class OriginalPos
{
public Rect pos;
public Scope scope;
public StackNode stack;
public int stackIndex;
public bool dragStarted;
}
private IDropTarget m_PrevDropTarget;
private GraphViewChange m_GraphViewChange;
private List<GraphElement> m_MovedElements;
private List<VisualElement> m_DropTargetPickList = new List<VisualElement>();
private GraphView m_GraphView;
private Dictionary<GraphElement, OriginalPos> m_OriginalPos;
private Vector2 m_originalMouse;
internal const int k_PanAreaWidth = 100;
internal const int k_PanSpeed = 4;
internal const int k_PanInterval = 10;
internal const float k_MinSpeedFactor = 0.5f;
internal const float k_MaxSpeedFactor = 2.5f;
internal const float k_MaxPanSpeed = 10f;
private IVisualElementScheduledItem m_PanSchedule;
private Vector3 m_PanDiff = Vector3.zero;
private Vector3 m_ItemPanDiff = Vector3.zero;
private Vector2 m_MouseDiff = Vector2.zero;
private GraphElement selectedElement { get; set; }
private GraphElement clickedElement { get; set; }
private IDropTarget GetDropTargetAt(Vector2 mousePosition, IEnumerable<VisualElement> exclusionList)
{
List<VisualElement> dropTargetPickList = m_DropTargetPickList;
dropTargetPickList.Clear();
base.target.panel.PickAll(mousePosition, dropTargetPickList);
IDropTarget dropTarget = null;
for (int i = 0; i < dropTargetPickList.Count; i++)
{
if (dropTargetPickList[i] == base.target && base.target != m_GraphView)
{
continue;
}
VisualElement visualElement = dropTargetPickList[i];
dropTarget = visualElement as IDropTarget;
if (dropTarget != null)
{
if (!exclusionList.Contains(visualElement))
{
break;
}
dropTarget = null;
}
}
return dropTarget;
}
//
// 摘要:
// SelectionDragger's constructor.
public FSMSelectionDragger()
{
base.activators.Add(new ManipulatorActivationFilter
{
button = MouseButton.LeftMouse
});
base.activators.Add(new ManipulatorActivationFilter
{
button = MouseButton.LeftMouse,
modifiers = EventModifiers.Shift
});
if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer)
{
base.activators.Add(new ManipulatorActivationFilter
{
button = MouseButton.LeftMouse,
modifiers = EventModifiers.Command
});
}
else
{
base.activators.Add(new ManipulatorActivationFilter
{
button = MouseButton.LeftMouse,
modifiers = EventModifiers.Control
});
}
base.panSpeed = new Vector2(1f, 1f);
base.clampToParentEdges = false;
m_MovedElements = new List<GraphElement>();
m_GraphViewChange.movedElements = m_MovedElements;
}
//
// 摘要:
// Called to register click event callbacks on the target element.
protected override void RegisterCallbacksOnTarget()
{
ISelection selection = base.target as ISelection;
if (selection == null)
{
throw new InvalidOperationException("Manipulator can only be added to a control that supports selection");
}
base.target.RegisterCallback<MouseDownEvent>(OnMouseDown);
base.target.RegisterCallback<MouseMoveEvent>(OnMouseMove);
base.target.RegisterCallback<MouseUpEvent>(OnMouseUp);
base.target.RegisterCallback<KeyDownEvent>(OnKeyDown);
base.target.RegisterCallback<MouseCaptureOutEvent>(OnMouseCaptureOutEvent);
}
//
// 摘要:
// Called to unregister event callbacks from the target element.
protected override void UnregisterCallbacksFromTarget()
{
base.target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
base.target.UnregisterCallback<MouseMoveEvent>(OnMouseMove);
base.target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
base.target.UnregisterCallback<KeyDownEvent>(OnKeyDown);
base.target.UnregisterCallback<MouseCaptureOutEvent>(OnMouseCaptureOutEvent);
}
private static void SendDragAndDropEvent(IDragAndDropEvent evt, List<ISelectable> selection, IDropTarget dropTarget, ISelection dragSource)
{
if (dropTarget == null)
{
return;
}
EventBase eventBase = evt as EventBase;
if (eventBase.eventTypeId == EventBase<DragExitedEvent>.TypeId())
{
dropTarget.DragExited();
}
else if (eventBase.eventTypeId == EventBase<DragEnterEvent>.TypeId())
{
dropTarget.DragEnter(evt as DragEnterEvent, selection, dropTarget, dragSource);
}
else if (eventBase.eventTypeId == EventBase<DragLeaveEvent>.TypeId())
{
dropTarget.DragLeave(evt as DragLeaveEvent, selection, dropTarget, dragSource);
}
if (dropTarget.CanAcceptDrop(selection))
{
if (eventBase.eventTypeId == EventBase<DragPerformEvent>.TypeId())
{
dropTarget.DragPerform(evt as DragPerformEvent, selection, dropTarget, dragSource);
}
else if (eventBase.eventTypeId == EventBase<DragUpdatedEvent>.TypeId())
{
dropTarget.DragUpdated(evt as DragUpdatedEvent, selection, dropTarget, dragSource);
}
}
}
private void OnMouseCaptureOutEvent(MouseCaptureOutEvent e)
{
if (m_Active)
{
if (m_PrevDropTarget != null && m_GraphView != null && m_PrevDropTarget.CanAcceptDrop(m_GraphView.selection))
{
m_PrevDropTarget.DragExited();
}
selectedElement = null;
m_PrevDropTarget = null;
m_Active = false;
}
}
//
// 摘要:
// Called on mouse down event.
//
// 参数:
// e:
// The event.
protected new void OnMouseDown(MouseDownEvent e)
{
if (m_Active)
{
e.StopImmediatePropagation();
}
else
{
if (!CanStartManipulation(e))
{
return;
}
m_GraphView = base.target as GraphView;
if (m_GraphView == null)
{
return;
}
selectedElement = null;
clickedElement = e.target as GraphElement;
if (clickedElement == null)
{
VisualElement visualElement = e.target as VisualElement;
clickedElement = visualElement.GetFirstAncestorOfType<GraphElement>();
if (clickedElement == null)
{
return;
}
}
if (!clickedElement.IsMovable() || !clickedElement.HitTest(clickedElement.WorldToLocal(e.mousePosition)))
{
return;
}
if (!m_GraphView.selection.Contains(clickedElement))
{
e.StopImmediatePropagation();
return;
}
selectedElement = clickedElement;
m_OriginalPos = new Dictionary<GraphElement, OriginalPos>();
foreach (ISelectable item in m_GraphView.selection)
{
GraphElement graphElement = item as GraphElement;
if (graphElement == null || !graphElement.IsMovable())
{
continue;
}
StackNode stackNode = null;
if (graphElement.parent is StackNode)
{
stackNode = graphElement.parent as StackNode;
if (stackNode.IsSelected(m_GraphView))
{
continue;
}
}
Rect position = graphElement.GetPosition();
Rect pos = graphElement.hierarchy.parent.ChangeCoordinatesTo(m_GraphView.contentViewContainer, position);
m_OriginalPos[graphElement] = new OriginalPos
{
pos = pos,
scope = graphElement.GetContainingScope(),
stack = stackNode,
stackIndex = (stackNode?.IndexOf(graphElement) ?? (-1))
};
}
m_originalMouse = e.mousePosition;
m_ItemPanDiff = Vector3.zero;
if (m_PanSchedule == null)
{
m_PanSchedule = m_GraphView.schedule.Execute(Pan).Every(10L).StartingIn(10L);
m_PanSchedule.Pause();
}
m_Active = true;
base.target.CaptureMouse();
e.StopImmediatePropagation();
}
}
internal Vector2 GetEffectivePanSpeed(Vector2 mousePos)
{
Vector2 vector = Vector2.zero;
if (mousePos.x <= 100f)
{
vector.x = (0f - ((100f - mousePos.x) / 100f + 0.5f)) * 4f;
}
else if (mousePos.x >= m_GraphView.contentContainer.layout.width - 100f)
{
vector.x = ((mousePos.x - (m_GraphView.contentContainer.layout.width - 100f)) / 100f + 0.5f) * 4f;
}
if (mousePos.y <= 100f)
{
vector.y = (0f - ((100f - mousePos.y) / 100f + 0.5f)) * 4f;
}
else if (mousePos.y >= m_GraphView.contentContainer.layout.height - 100f)
{
vector.y = ((mousePos.y - (m_GraphView.contentContainer.layout.height - 100f)) / 100f + 0.5f) * 4f;
}
vector = Vector2.ClampMagnitude(vector, 10f);
return vector;
}
//
// 摘要:
// Called on mouse move event.
//
// 参数:
// e:
// The event.
protected new void OnMouseMove(MouseMoveEvent e)
{
if (!m_Active || m_GraphView == null)
{
return;
}
VisualElement src = (VisualElement)e.target;
Vector2 mousePos = src.ChangeCoordinatesTo(m_GraphView.contentContainer, e.localMousePosition);
m_PanDiff = GetEffectivePanSpeed(mousePos);
if (m_PanDiff != Vector3.zero)
{
m_PanSchedule.Resume();
}
else
{
m_PanSchedule.Pause();
}
m_MouseDiff = m_originalMouse - e.mousePosition;
Dictionary<Group, List<GraphElement>> dictionary = (e.shiftKey ? new Dictionary<Group, List<GraphElement>>() : null);
foreach (KeyValuePair<GraphElement, OriginalPos> originalPo in m_OriginalPos)
{
GraphElement key = originalPo.Key;
if (key.hierarchy.parent == null)
{
continue;
}
if (!originalPo.Value.dragStarted)
{
key.GetFirstAncestorOfType<StackNode>()?.OnStartDragging(key);
if (dictionary != null)
{
Group group = key.GetContainingScope() as Group;
if (group != null)
{
if (!dictionary.ContainsKey(group))
{
dictionary[group] = new List<GraphElement>();
}
dictionary[group].Add(key);
}
}
originalPo.Value.dragStarted = true;
}
MoveElement(key, originalPo.Value.pos);
}
List<ISelectable> selection = m_GraphView.selection;
IDropTarget dropTargetAt = GetDropTargetAt(e.mousePosition, selection.OfType<VisualElement>());
m_PrevDropTarget = dropTargetAt;
selectedElement = null;
e.StopPropagation();
}
private void Pan(TimerState ts)
{
//m_GraphView.viewTransform.position -= m_PanDiff;
//m_ItemPanDiff += m_PanDiff;
//foreach (KeyValuePair<GraphElement, OriginalPos> originalPo in m_OriginalPos)
//{
// MoveElement(originalPo.Key, originalPo.Value.pos);
//}
}
private void MoveElement(GraphElement element, Rect originalPos)
{
Matrix4x4 worldTransform = element.worldTransform;
Vector3 vector = new Vector3(worldTransform.m00, worldTransform.m11, worldTransform.m22);
Rect rect = new Rect(0f, 0f, originalPos.width, originalPos.height);
rect.x = originalPos.x - (m_MouseDiff.x - m_ItemPanDiff.x) * base.panSpeed.x / vector.x * element.transform.scale.x;
rect.y = originalPos.y - (m_MouseDiff.y - m_ItemPanDiff.y) * base.panSpeed.y / vector.y * element.transform.scale.y;
element.SetPosition(m_GraphView.contentViewContainer.ChangeCoordinatesTo(element.hierarchy.parent, rect));
}
//
// 摘要:
// Called on mouse up event.
//
// 参数:
// e:
// The event.
//
// evt:
protected new void OnMouseUp(MouseUpEvent evt)
{
if (m_GraphView == null)
{
if (m_Active)
{
base.target.ReleaseMouse();
selectedElement = null;
m_Active = false;
m_PrevDropTarget = null;
}
return;
}
List<ISelectable> selection = m_GraphView.selection;
if (!CanStopManipulation(evt))
{
return;
}
if (m_Active)
{
if (selectedElement == null)
{
m_MovedElements.Clear();
foreach (IGrouping<StackNode, GraphElement> item in from v in m_OriginalPos
group v.Key by v.Value.stack)
{
if (item.Key != null && m_GraphView.elementsRemovedFromStackNode != null)
{
m_GraphView.elementsRemovedFromStackNode(item.Key, item);
}
foreach (GraphElement item2 in item)
{
item2.UpdatePresenterPosition();
}
m_MovedElements.AddRange(item);
}
GraphView graphView = base.target as GraphView;
if (graphView != null && graphView.graphViewChanged != null)
{
KeyValuePair<GraphElement, OriginalPos> keyValuePair = m_OriginalPos.First();
m_GraphViewChange.moveDelta = keyValuePair.Key.GetPosition().position - keyValuePair.Value.pos.position;
graphView.graphViewChanged(m_GraphViewChange);
}
}
m_PanSchedule.Pause();
if (m_ItemPanDiff != Vector3.zero)
{
Vector3 position = m_GraphView.contentViewContainer.transform.position;
Vector3 scale = m_GraphView.contentViewContainer.transform.scale;
m_GraphView.UpdateViewTransform(position, scale);
}
base.target.ReleaseMouse();
evt.StopPropagation();
}
selectedElement = null;
m_Active = false;
m_PrevDropTarget = null;
}
private void OnKeyDown(KeyDownEvent e)
{
if (e.keyCode != KeyCode.Escape || m_GraphView == null || !m_Active)
{
return;
}
Dictionary<Scope, List<GraphElement>> dictionary = new Dictionary<Scope, List<GraphElement>>();
foreach (KeyValuePair<GraphElement, OriginalPos> originalPo in m_OriginalPos)
{
OriginalPos value = originalPo.Value;
if (value.stack != null)
{
value.stack.InsertElement(value.stackIndex, originalPo.Key);
continue;
}
if (value.scope != null)
{
if (!dictionary.ContainsKey(value.scope))
{
dictionary[value.scope] = new List<GraphElement>();
}
dictionary[value.scope].Add(originalPo.Key);
}
originalPo.Key.SetPosition(value.pos);
}
foreach (KeyValuePair<Scope, List<GraphElement>> item in dictionary)
{
item.Key.AddElements(item.Value);
}
m_PanSchedule.Pause();
if (m_ItemPanDiff != Vector3.zero)
{
Vector3 position = m_GraphView.contentViewContainer.transform.position;
Vector3 scale = m_GraphView.contentViewContainer.transform.scale;
m_GraphView.UpdateViewTransform(position, scale);
}
using (DragExitedEvent evt = EventBase<DragExitedEvent>.GetPooled())
{
List<ISelectable> selection = m_GraphView.selection;
SendDragAndDropEvent(evt, selection, m_PrevDropTarget, m_GraphView);
}
base.target.ReleaseMouse();
e.StopPropagation();
}
}
}

View File

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

View File

@@ -0,0 +1,379 @@
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMStateGraphView : GraphView
{
public Dictionary<string, FSMNodeView> StateNodes = new Dictionary<string, FSMNodeView>();
internal FSMTransitionBackground transition = null;
internal FSMRectangleSelector selector;
public bool isMakeTransition = false;
public FSMNodeView MakeTransitionFrom = null;
public FSMNodeView HoverNode = null;
private RuntimeFSMController controller = null;
//private FSMNodeView selectNode = null;
public FSMStateGraphView()
{
FSMGridBackground background = new FSMGridBackground();
Insert(0, background);
transition = new FSMTransitionBackground();
Insert(1, transition);
selector = new FSMRectangleSelector();
Insert(3, selector);
RegisterCallback<KeyDownEvent>(KeyDownControl);
RegisterCallback<MouseDownEvent>(MouseDownControl);
this.AddManipulator(new ContentDragger());
this.AddManipulator(new FSMSelectionDragger());
ContentZoomer zoomer = new ContentZoomer();
zoomer.minScale = 0.1f;
zoomer.maxScale = 3;
this.AddManipulator(zoomer);
RefreshView();
}
private void RefreshView()
{
if (Context.Instance.RuntimeFSMController != null)
{
// 默认位置和缩放
viewTransform.position = Context.Instance.RuntimeFSMController.viewPosition;
viewTransform.scale = Context.Instance.RuntimeFSMController.viewScale;
}
controller = Context.Instance.RuntimeFSMController;
RefreshNodes();
}
private void SaveScaleAndPosition() {
if (viewTransform == null || Context.Instance.RuntimeFSMController == null)
return;
if (Context.Instance.RuntimeFSMController.viewScale != viewTransform.scale)
{
Context.Instance.RuntimeFSMController.viewScale = viewTransform.scale;
Context.Instance.RuntimeFSMController.Save();
}
if (Context.Instance.RuntimeFSMController.viewPosition != viewTransform.position)
{
Context.Instance.RuntimeFSMController.viewPosition = viewTransform.position;
Context.Instance.RuntimeFSMController.Save();
}
}
public void Update()
{
if (controller != Context.Instance.RuntimeFSMController)
{
RefreshView();
controller = Context.Instance.RuntimeFSMController;
}
SaveScaleAndPosition();
}
public void RefreshNodes()
{
foreach (var item in StateNodes.Values)
{
RemoveElement(item);
}
StateNodes.Clear();
List<FSMStateNodeData> datas = Context.Instance.GetCurrentShowStateNodeData();
if (datas == null || datas.Count == 0)
return;
//selectNode = null;
foreach (var item in datas)
{
FSMNodeView node = new FSMNodeView(item,this);
node.title = item.DisplayName;
node.SetPosition(item.rect);
this.AddElement(node);
StateNodes.Add(item.name, node);
if (GetPrefsSelection(item.name))
{
AddToSelection(node);
}
}
}
public void RenameState(string oldName,string newName)
{
//Debug.LogFormat("重命名:old:{0} new:{1} cn:{2} co:{3}",oldName,newName, StateNodes.ContainsKey(newName), StateNodes.ContainsKey(oldName));
if (StateNodes.ContainsKey(newName))
return;
if (!StateNodes.ContainsKey(oldName))
return;
StateNodes.Add(newName, StateNodes[oldName]);
StateNodes.Remove(oldName);
}
public FSMNodeView GetNode(string name)
{
if (string.IsNullOrEmpty(name))
return null;
if (StateNodes.ContainsKey(name))
return StateNodes[name];
return null;
}
private void KeyDownControl(KeyDownEvent evt)
{
if (evt.keyCode == KeyCode.Delete)
{
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
if (controller == null) return;
// 删除选中的过渡
if (transition.Selection != null && controller != null)
FSMTransitionFactory.DeleteTransition(controller, transition.Selection);
RefreshNodes();
}
}
private void MouseDownControl(MouseDownEvent evt)
{
//BehaviourTreeView.TreeWindow.WindowRoot.InspectorView.UpdateInspector();
if (evt.button == 0 && evt.clickCount == 1)
{
// 左键单击
transition.OnTransitionSelection(transition.CloseTransition);
StopMakeTransition(null);
}
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
FSMNodeView node = evt.target as FSMNodeView;
if (node != null)
transition.OnTransitionSelection(null);
int count = evt.menu.MenuItems().Count;
for (int i = 0; i < count; i++)
{
evt.menu.RemoveItemAt(0);
}
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
bool disable = controller == null || EditorApplication.isPlaying;
DropdownMenuAction.Status status = disable ? DropdownMenuAction.Status.Disabled : DropdownMenuAction.Status.Normal;
if (node == null)
{
//Debug.LogFormat("鼠标位置:{0}",Event.current.mousePosition);
evt.menu.AppendAction("Create State", CreateState, (d) => status, Event.current.mousePosition);
evt.menu.AppendAction("Create Sub-State Machine", CreateSubStateMachine, (d) => status, Event.current.mousePosition);
}
else {
node.ShowMenu(evt);
}
//base.BuildContextualMenu
}
public void CreateState(DropdownMenuAction action)
{
Vector2 mousePosition = (Vector2)(action.userData);
mousePosition.Set(mousePosition.x - parent.layout.x, mousePosition.y - layout.y - 20);
Vector2 position = contentViewContainer.transform.matrix.inverse.MultiplyPoint(mousePosition);
CreateState(false, position);
}
public void CreateSubStateMachine(DropdownMenuAction action) {
Vector2 mousePosition = (Vector2)(action.userData);
mousePosition.Set(mousePosition.x - parent.layout.x, mousePosition.y - layout.y - 20);
Vector2 position = contentViewContainer.transform.matrix.inverse.MultiplyPoint(mousePosition);
CreateState(true, position);
}
private void CreateState(bool isSubStateMachine, Vector3 mousePosition)
{
Rect rect = new Rect(0, 0, FSMConst.StateNodeWith, FSMConst.StateNodeHeight);
rect.center = mousePosition;
List<FSMStateNodeData> states = Context.Instance.GetCurrentShowStateNodeData();
bool isDefaultState = states.Count == 2; // 这里是为了兼容旧的配置文件
if (states != null)
{
bool isAllBuildIn = true;
foreach (var item in states)
{
if (!item.isBuildInState)
{
isAllBuildIn = false;
break;
}
}
if (isAllBuildIn) isDefaultState = true;
}
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
List<string> parents = new List<string>();
parents.AddRange(Context.Instance.Layers);
FSMStateNodeData state = FSMStateNodeFactory.CreateStateNode(controller, rect, isDefaultState, isSubStateMachine, parents);
if (isSubStateMachine)
{
// 给当前子状态机创建 Entry 状态
Rect r = new Rect(0, 300, FSMConst.StateNodeWith, FSMConst.StateNodeHeight);
CreateSubState(controller, FSMConst.entryState, state, parents, r, FSMConst.entryState);
// 给当前子状态机创建 Any 状态
r = new Rect(0, 100, FSMConst.StateNodeWith, FSMConst.StateNodeHeight);
CreateSubState(controller, FSMConst.anyState, state, parents, r, FSMConst.anyState);
// 给当前子状态机创建 Entry 状态
r = new Rect(600, 300, FSMConst.StateNodeWith, FSMConst.StateNodeHeight);
CreateSubState(controller, FSMConst.up, state, parents, r, FSMConst.up);
}
RefreshNodes();
}
private void CreateSubState(RuntimeFSMController controller, string name, FSMStateNodeData state, List<string> parents, Rect rect, string buildInName)
{
// 创建三个内置状态
List<string> parents_temp = new List<string>();
parents_temp.AddRange(parents);
parents_temp.Add(state.name);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < parents_temp.Count; i++)
{
stringBuilder.Append(parents_temp[i]);
stringBuilder.Append("/");
}
stringBuilder.Append(name);
FSMStateNodeFactory.CreateStateNode(controller, stringBuilder.ToString(), rect, false, false, parents_temp, true, buildInName);
}
public void StartMakeTransition(FSMNodeView node)
{
isMakeTransition = true;
MakeTransitionFrom = node;
}
public void StopMakeTransition(FSMNodeView node)
{
if (node == MakeTransitionFrom)
return;
isMakeTransition = false;
HoverNode = null;
if (node == null)
return;
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
if (controller == null)
return;
FSMTransitionFactory.CreateTransition(controller, MakeTransitionFrom.Data.name, node.Data.name);
}
public void OnGUI() {
// 取消拖拽
if (Event.current.type == EventType.MouseLeaveWindow && Event.current.button == 0)
{
selector.CancelDrag();
}
if (Event.current.type == EventType.MouseUp && Event.current.button == 0)
{
selector.CancelDrag();
}
}
protected override void ExecuteDefaultAction(EventBase evt)
{
base.ExecuteDefaultAction(evt);
selector.ExecuteAction(evt);
}
internal static bool GetPrefsSelection(string name) {
string key = PrefsSelectionKey(name);
if (string.IsNullOrEmpty(key))
return false;
bool v = EditorPrefs.GetBool(key, false);
if (v)
EditorPrefs.DeleteKey(key);
return v;
}
internal static void SavePrefsSelection(string name)
{
string key = PrefsSelectionKey(name);
if (string.IsNullOrEmpty(key))
return;
EditorPrefs.SetBool(key, true);
}
internal static string PrefsSelectionKey(string name)
{
RuntimeFSMController controller = Context.Instance.RuntimeFSMController;
if (controller == null)
return string.Empty;
return string.Format("XFFSM:{0}:{1}",controller.name,name);
}
}
}

View File

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

View File

@@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Graphs;
using UnityEngine;
using UnityEngine.UIElements;
namespace XFFSM
{
public class FSMTransitionBackground : ImmediateModeElement
{
private float edgeDistanceMultiplier => Mathf.Clamp(graphView.scale, 0.1f, 1);
private float edgeSizeMultiplier => Mathf.Clamp( graphView.scale,0.1f,1);
private static Slot s_TargetDraggingSlot;
private FSMStateGraphView graphView;
private static Vector3 edgeToSelfOffsetVector => new Vector3(0f, 30f, 0f);
private static Color selectedEdgeColor => new Color(0.42f, 0.7f, 1f, 1f);
public FSMTransitionData CloseTransition { get;internal set; }
public FSMTransitionData Selection { get; set; }
private FSMTransitionData entryToDefault = new FSMTransitionData();
private Vector3[] vectors = new Vector3[2];
private Vector3[] points = new Vector3[2];
private static Color defaultTransitionColor => new Color(0.6f, 0.4f, 0f, 1f);
private static FSMTransitionData current_change_transition;
private float current_change_transition_timer = 0;
#region 退
private FSMStateNode currentState;
private bool state_exiting = false;
private string exit_state_parent;
private string exit_state_name;
private string exit_state_to_name;
private float exit_state_timer = 0;
#endregion
// Fix编码
protected override void ImmediateRepaint()
{
List<FSMTransitionData> transitions = Context.Instance.GetCurrentShowTransitionData();
//if (transitions == null || transitions.Count == 0)
// return;
if (Event.current.type == EventType.Repaint)
{
VisualElement visualElement = base.parent;
graphView = visualElement as FSMStateGraphView;
if (graphView == null)
throw new InvalidOperationException("FSMTransitionBackground can only be added to a GraphView");
if (transitions != null)
{
foreach (var transition in transitions)
{
DrawTransiton(transition,Color.white);
DrawCurrentTransition(transition);
}
}
List<FSMStateNodeData> nodes = Context.Instance.GetCurrentShowStateNodeData();
if (nodes != null)
{
entryToDefault.fromStateName = string.Empty;
entryToDefault.toStateName = string.Empty;
foreach (var item in nodes)
{
if (item.IsEntryState)
entryToDefault.fromStateName = item.name;
if(item.defaultState)
entryToDefault.toStateName = item.name;
}
DrawTransiton(entryToDefault, defaultTransitionColor);
}
DrawMakeTransition();
DrawStateExitTransition();
}
if(graphView.HoverNode == null)
CloseTransition = FindClosestTransition();
}
private void DrawTransiton(FSMTransitionData data,Color color )
{
FSMNodeView fromNode = graphView.GetNode(data.fromStateName);
FSMNodeView toNode = graphView.GetNode(data.toStateName);
if (fromNode == null || toNode == null)
return;
if (data == Selection)
color = selectedEdgeColor;
Vector3[] edgePoints = GetTransitionPoints(data );
DrawTransiton(edgePoints, color, data == CloseTransition, true);
}
private void DrawTransiton(Vector3[] edgePoints ,Color color,bool bold,bool isDrawArrow)
{
Texture2D tex = (Texture2D)Styles.connectionTexture.image;
float arrowSize = 5f * edgeSizeMultiplier;
float outlineWidth = 2f * edgeSizeMultiplier;
float arrowLength = 13f * edgeSizeMultiplier;
Handles.color = color;
float width = 10f * edgeSizeMultiplier;
if (bold)
{
arrowSize *= 1.5f;
width *= 1.5f;
}
Handles.DrawAAPolyLine(tex, width, edgePoints[0], edgePoints[1]);
if (isDrawArrow) {
Vector3 cross = Vector3.Cross((edgePoints[0] - edgePoints[1]).normalized, Vector3.forward);
DrawArrows(color, cross, edgePoints, isSelf: false, arrowSize, outlineWidth, arrowLength);
}
}
private Vector3[] GetTransitionPoints(FSMTransitionData data )
{
return GetTransitionPoints(data.fromStateName, data.toStateName);
}
private Vector3[] GetTransitionPoints(string fromStateName,string toStateName)
{
FSMNodeView fromNode = graphView.GetNode(fromStateName);
FSMNodeView toNode = graphView.GetNode(toStateName);
if (fromNode == null || toNode == null)
return null;
float num = 5f * edgeDistanceMultiplier;
points[0] = GetNodeViewPosition(fromNode);
points[1] = GetNodeViewPosition(toNode);
Vector3 cross = Vector3.Cross((points[0] - points[1]).normalized, Vector3.forward);
points[0] += cross * num;
points[1] += cross * num;
return points;
}
private Vector3 GetNodeViewPosition(FSMNodeView node)
{
return graphView.contentViewContainer.transform.matrix.MultiplyPoint(node.GetPosition().center);
}
private static void DrawArrows(Color color, Vector3 cross, Vector3[] edgePoints, bool isSelf, float arrowSize, float outlineWidth, float arrowLength)
{
Vector3 vector = edgePoints[1] - edgePoints[0];
Vector3 normalized = vector.normalized;
Vector3 vector2 = vector * 0.5f + edgePoints[0];
vector2 -= cross * 0.5f;
float num = Mathf.Min(arrowLength * 1.5f, (vector2 - edgePoints[0]).magnitude) * 0.66f;
int num2 = 1;
for (int i = 0; i < num2; i++)
{
Color color2 = color;
Vector3 center = vector2 + (float)((num2 == 1) ? i : (i - 1)) * num * (isSelf ? cross : normalized);
DrawArrow(color2, cross, normalized, center, arrowSize, outlineWidth);
}
}
private static void DrawArrow(Color color, Vector3 cross, Vector3 direction, Vector3 center, float arrowSize, float outlineWidth)
{
if (Event.current.type == EventType.Repaint)
{
Vector3[] array = new Vector3[4];
array[0] = center + direction * arrowSize;
array[1] = center - direction * arrowSize + cross * arrowSize;
array[2] = center - direction * arrowSize - cross * arrowSize;
array[3] = array[0];
Shader.SetGlobalColor("_HandleColor", color);
Handles.color = color;
Handles.DrawAAPolyLine((Texture2D)Styles.connectionTexture.image, outlineWidth, array);
Handles.DrawAAConvexPolygon(array);
}
}
public FSMTransitionData FindClosestTransition()
{
FSMTransitionData result = null;
float num = float.PositiveInfinity;
Vector3 vector = Event.current.mousePosition;
List<FSMTransitionData> transitions = Context.Instance.GetCurrentShowTransitionData();
if (transitions == null || transitions.Count == 0)
return null;
foreach (var transition in transitions)
{
Vector3[] edgePoints = GetTransitionPoints(transition);
if(edgePoints == null) continue;
float num2 = float.PositiveInfinity;
num2 = ((!(edgePoints[0] == edgePoints[1])) ? HandleUtility.DistancePointLine(vector, edgePoints[0], edgePoints[1]) : Vector3.Distance(edgeToSelfOffsetVector + edgePoints[0], vector));
if (num2 < num && num2 < 10f)
{
num = num2;
result = transition;
}
}
return result;
}
public void OnTransitionSelection(FSMTransitionData transition)
{
if (this.Selection != null && transition == null)
{
FSMTransitionInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, null);
}
this.Selection = transition;
//Debug.Log("OnTransitionSelection");
if(Selection != null)
{
EditorApplication.delayCall -= DelayCallSelection;
EditorApplication.delayCall += DelayCallSelection;
}
}
private void DrawMakeTransition()
{
if (!graphView.isMakeTransition)
return;
vectors[0] = GetNodeViewPosition(graphView.MakeTransitionFrom);
if (graphView.HoverNode != null && !graphView.HoverNode.Data.isBuildInState)
vectors[1] = GetNodeViewPosition(graphView.HoverNode);
else
vectors[1] = Event.current.mousePosition;
DrawTransiton(vectors , Color.white,false, true);
}
/// <summary>
/// 绘制当前状态切换的过渡
/// </summary>
private void DrawCurrentTransition(FSMTransitionData transition )
{
if (Context.Instance.FSMController == null)
return;
if (Context.Instance.FSMController.RuntimeFSMController == null)
return;
if (Context.Instance.RuntimeFSMController == null)
return;
float width = 10f * edgeSizeMultiplier;
if (CloseTransition == transition)
width *= 1.5f;
Vector3[] edgePoints = GetTransitionPoints(transition);
int index = Context.Instance.FSMController.RuntimeFSMController.IndexOf(Context.Instance.RuntimeFSMController);
// 找到当前的过渡
FSMTransition current_transition = Context.Instance.FSMController.GetCurrentTransition(index);
if (current_transition == null) return;
if (!transition.Key.Equals(current_transition.Data.Key)) return;
if (current_change_transition != current_transition.Data)
{
current_change_transition = current_transition.Data;
current_change_transition_timer = 0;
}
if (current_change_transition.Key.Equals(current_transition.Data.Key) && current_change_transition_timer >= 1)
return;
FSMStateNodeData from = Context.Instance.RuntimeFSMController.GetStateNodeData(current_change_transition.fromStateName);
if (from == null || from.Parent != Context.Instance.LayerParent)
{
current_change_transition_timer = 1;
return;
}
current_change_transition_timer += Time.unscaledDeltaTime * 3;
if (edgePoints != null && edgePoints.Length >= 2)
{
Handles.color = selectedEdgeColor;
Handles.DrawAAPolyLine(width, edgePoints[0], Vector2.Lerp(edgePoints[0], edgePoints[1], current_change_transition_timer));
}
}
private void DrawStateExitTransition()
{
if (Event.current.type != EventType.Repaint)
return;
if (!Application.isPlaying) return;
if (Context.Instance.FSMController == null)
return;
if (Context.Instance.FSMController.RuntimeFSMController == null)
return;
if (Context.Instance.RuntimeFSMController == null)
return;
float width = 10f * edgeSizeMultiplier;
int index = Context.Instance.FSMController.RuntimeFSMController.IndexOf(Context.Instance.RuntimeFSMController);
FSMStateNode stateNode = Context.Instance.FSMController.GetCurrentStateInfo(index, Context.Instance.LayerParent);
if (currentState != null && stateNode == null)
{
state_exiting = true;
exit_state_parent = currentState.data.Parent;
exit_state_name = currentState.data.name;
exit_state_timer = 0;
List<FSMStateNodeData> nodes = Context.Instance.GetCurrentShowStateNodeData();
if (nodes != null)
{
foreach (var item in nodes)
{
if (item.isBuildInState && item.buildInStateName.Equals(FSMConst.up))
{
exit_state_to_name = item.name;
break;
}
}
}
}
if (state_exiting)
{
exit_state_timer += Time.unscaledDeltaTime * 3;
Handles.color = selectedEdgeColor;
Vector3[] edgePoints = GetTransitionPoints(exit_state_name, exit_state_to_name);
if(edgePoints != null)
Handles.DrawAAPolyLine(width, edgePoints[0], Vector2.Lerp(edgePoints[0], edgePoints[1], exit_state_timer));
if (exit_state_timer >= 1 || !exit_state_parent.Equals(Context.Instance.LayerParent))
{
state_exiting = false;
exit_state_parent = null;
exit_state_name = null;
exit_state_to_name = null;
exit_state_timer = 0;
}
}
currentState = stateNode;
}
private void DelayCallSelection()
{
FSMTransitionInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, Selection);
}
}
}

View File

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