using System; using System.Collections.Generic; using System.Linq; using AlicizaX.AnimationFlow.Runtime; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace AlicizaX.AnimationFlow.Editor { public class GraphWindow : EditorWindow { private GraphInspector graphInspector; private GraphView graphContentView; private Runtime.AnimationFlow animationFlowComponent; private float editorPreviousTime; private bool _subScribeEditorEventState; [MenuItem("Window/AnimationGraph")] public static void Open() { GetWindow("AnimationFlow"); } private void Update() { if (graphContentView == null || animationFlowComponent == null || Application.isPlaying) { return; } if (animationFlowComponent.InPlaying) { float delta = (Time.realtimeSinceStartup - editorPreviousTime) * Time.timeScale; editorPreviousTime = Time.realtimeSinceStartup; animationFlowComponent.Tick(delta); } List nodes = new List(); foreach (var VARIABLE in animationFlowComponent.AnimationNodes) { nodes.Add(VARIABLE); } UpdateNodeState(nodes); } private void UpdateNodeState(List nodes) { foreach (var node in nodes) { switch (node.State) { case EState.Enter: graphContentView?.OnNodeEnter(node); break; case EState.Running: graphContentView?.OnNodeUpdate(node); break; case EState.Exit: graphContentView?.OnNodeExit(node); break; ; } if (node.Childs.Count > 0) { UpdateNodeState(node.Childs); } } } private void OnEnable() { animationFlowComponent = null; BuildView(); CheckSelectionAnimationFlow(); Selection.selectionChanged -= OnSelectionChanged; Selection.selectionChanged += OnSelectionChanged; Undo.undoRedoPerformed -= UndoRedoPerformed; Undo.undoRedoPerformed += UndoRedoPerformed; EditorApplication.playModeStateChanged -= OnModeStateChanged; EditorApplication.playModeStateChanged += OnModeStateChanged; } private void OnDisable() { Selection.selectionChanged -= OnSelectionChanged; Undo.undoRedoPerformed -= UndoRedoPerformed; EditorApplication.playModeStateChanged -= OnModeStateChanged; if (animationFlowComponent != null) { animationFlowComponent.ResetNode(); } } /// /// 生成View /// private void BuildView() { if (!EditorResourceTool.LocateEditorAssets()) { return; } Texture2D btnPlayIcon = EditorGUIUtility.FindTexture("d_PlayButton"); Texture2D btnPauseIcon = EditorGUIUtility.FindTexture("d_PauseButton"); Texture2D btnStepIcon = EditorGUIUtility.FindTexture("d_StepButton"); Texture2D btnSaveIcon = EditorGUIUtility.FindTexture("SaveActive"); VisualTreeAsset visual_tree = AssetDatabase.LoadAssetAtPath(EditorResourceTool.editorAssets + "/UIGraphWindow.uxml"); visual_tree.CloneTree(rootVisualElement); graphInspector = new GraphInspector(); rootVisualElement.Q("Inspector").Add(graphInspector); VisualElement graph_parent = rootVisualElement.Q("Graph"); GUIStyle gui_style = new(); Texture2D texture = new(1, 1); texture.SetPixel(0, 0, new Color(0.25f, 0.25f, 0.25f, 1f)); texture.Apply(); gui_style.normal.background = texture; gui_style.padding = new RectOffset(5, 5, 4, 4); int index_name = 0; IMGUIContainer imgui_container = new(() => { if (animationFlowComponent == null) { graphContentView?.ClearGraph(); return; } GUILayout.BeginHorizontal(gui_style); List keys = new(); foreach (ActionNode baseData in animationFlowComponent.AnimationNodes) { if (baseData is EntryNode root && !string.IsNullOrEmpty(root.Name)) { keys.Add(root.Name); } } GUI.color = !animationFlowComponent.InPlaying && keys.Count > 0 ? Color.white : Color.gray; index_name = EditorGUILayout.Popup(index_name, keys.ToArray(), GUILayout.Width(100)); if (GUILayout.Button(btnPlayIcon)) { if (keys.Count > 0) { if (animationFlowComponent.InPlaying) { animationFlowComponent.Stop(); return; } OnBtnClickPlay(keys[index_name]); } } GUI.color = animationFlowComponent.InPlaying ? Color.white : Color.gray; if (GUILayout.Button(btnPauseIcon)) { OnBtnClickPause(); } GUI.color = animationFlowComponent.InPlaying || animationFlowComponent.InPause ? Color.white : Color.gray; if (GUILayout.Button(btnStepIcon)) { OnBtnClickStep(); } GUI.color = Color.white; GUILayout.EndHorizontal(); }); graph_parent.Add(imgui_container); imgui_container.style.position = Position.Absolute; imgui_container.style.bottom = 0; imgui_container.style.alignSelf = Align.Center; imgui_container.style.height = 40; graphContentView = new(this); graph_parent.Insert(0, graphContentView); } private void OnFocus() { CheckSelectionAnimationFlow(); } private void OnSelectionChanged() { CheckSelectionAnimationFlow(); } private void UndoRedoPerformed() { RePaintGraph(); } private void OnModeStateChanged(PlayModeStateChange _) { if (TryGetPlayerFromSelection()) { RePaintGraph(); } else { graphInspector.Clear(); graphContentView.ClearGraph(); } } /// /// 检查当前选中的物体是否存在AnimationFlow组件 /// private void CheckSelectionAnimationFlow() { if (TryGetPlayerFromSelection()) { RePaintGraph(); } } private void RePaintGraph() { List nodes = new List(); foreach (var VARIABLE in animationFlowComponent.AnimationNodes) { nodes.Add(VARIABLE); } CheckEmptyNode(nodes); graphInspector.Clear(); graphContentView.ClearGraph(); graphContentView.SetAnimationFlow(animationFlowComponent); } private void CheckEmptyNode(List nodes) { for (int i = nodes.Count - 1; i >= 0; i--) { if (nodes[i] == null) { nodes.RemoveAt(i); } if (nodes[i].Childs.Count > 0) { CheckEmptyNode(nodes[i].Childs); } } } private bool TryGetPlayerFromSelection() { if (Selection.activeGameObject != null) { Runtime.AnimationFlow new_animation_flow = Selection.activeGameObject.GetComponent(); if (new_animation_flow != null && (animationFlowComponent == null || new_animation_flow != animationFlowComponent)) { if (animationFlowComponent != null) { // DeleteAction(); } animationFlowComponent = new_animation_flow; return true; } } return false; } #region 行为树底部菜单响应事件 private void OnBtnClickPlay(string name) { if (graphContentView == null || animationFlowComponent == null) { return; } if (animationFlowComponent.AnimationNodes.Exists(v => !v.Valid())) { EditorUtility.DisplayDialog("Warning", "Please make sure the required parameters are set.", "ok"); return; } editorPreviousTime = Time.realtimeSinceStartup; ResetView(); animationFlowComponent.Play(name); } private void OnBtnClickPause() { if (graphContentView == null || animationFlowComponent == null || !animationFlowComponent.InPlaying) { return; } animationFlowComponent.AnimationFlowPlayebleType = EAnimationFlowPlayebleType.Pause; } private void OnBtnClickStep() { if (graphContentView == null || animationFlowComponent == null || !animationFlowComponent.InPlaying || !animationFlowComponent.InPause) { return; } animationFlowComponent.Tick(0.016f); } #endregion public void OnSelect(NodeView node_view) { graphInspector.DrawNode(node_view); } public void OnNodeRemove() { graphInspector.Clear(); } private void ResetView() { graphContentView?.ResetView(); } } }