From 11e5744b461920fc9f815adc150857e7bbf92088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <10001@qq.com> Date: Fri, 7 Feb 2025 16:05:13 +0800 Subject: [PATCH] init --- Editor.meta | 8 + Editor/AlicizaX.AnimationFlow.Editor.asmdef | 18 + .../AlicizaX.AnimationFlow.Editor.asmdef.meta | 7 + Editor/Data.meta | 8 + Editor/Data/AnimationFlowSerialize.cs | 11 + Editor/Data/AnimationFlowSerialize.cs.meta | 11 + Editor/Graph.meta | 8 + Editor/Graph/GraphView.cs | 367 ++++++++++++++++++ Editor/Graph/GraphView.cs.meta | 11 + Editor/Graph/NodeView.cs | 123 ++++++ Editor/Graph/NodeView.cs.meta | 11 + Editor/Graph/SearchWindowProvider.cs | 64 +++ Editor/Graph/SearchWindowProvider.cs.meta | 11 + Editor/Inspector.meta | 8 + Editor/Inspector/GraphInspector.cs | 45 +++ Editor/Inspector/GraphInspector.cs.meta | 11 + Editor/Misc.meta | 8 + Editor/Misc/EditorResourceTool.cs | 44 +++ Editor/Misc/EditorResourceTool.cs.meta | 11 + Editor/Styles.meta | 8 + Editor/Styles/AnimationFlowStyles.uss | 7 + Editor/Styles/AnimationFlowStyles.uss.meta | 11 + Editor/Styles/Complete.png | Bin 0 -> 18328 bytes Editor/Styles/Complete.png.meta | 98 +++++ Editor/Styles/SplitView.cs | 7 + Editor/Styles/SplitView.cs.meta | 3 + Editor/Styles/UICheckMark.png | Bin 0 -> 973 bytes Editor/Styles/UICheckMark.png.meta | 117 ++++++ Editor/Styles/UIGraphWindow.uxml | 6 + Editor/Styles/UIGraphWindow.uxml.meta | 10 + Editor/Styles/Warning.png | Bin 0 -> 20513 bytes Editor/Styles/Warning.png.meta | 98 +++++ Editor/Window.meta | 8 + Editor/Window/GraphWindow.cs | 344 ++++++++++++++++ Editor/Window/GraphWindow.cs.meta | 11 + LICENSE.md | 201 ++++++++++ LICENSE.md.meta | 7 + Runtime.meta | 8 + Runtime/AlicizaX.AnimationFlow.Runtime.asmdef | 14 + ...AlicizaX.AnimationFlow.Runtime.asmdef.meta | 7 + Runtime/AnimationFlow.cs | 265 +++++++++++++ Runtime/AnimationFlow.cs.meta | 11 + Runtime/Attribute.meta | 8 + Runtime/Attribute/CategoryAttribute.cs | 12 + Runtime/Attribute/CategoryAttribute.cs.meta | 11 + Runtime/Attribute/NameAttribute.cs | 12 + Runtime/Attribute/NameAttribute.cs.meta | 11 + Runtime/Core.meta | 8 + Runtime/Core/Animation.meta | 8 + Runtime/Core/Animation/CanvasGroupAlphaTo.cs | 54 +++ .../Core/Animation/CanvasGroupAlphaTo.cs.meta | 11 + Runtime/Core/Animation/GraphicAlphaTo.cs | 54 +++ Runtime/Core/Animation/GraphicAlphaTo.cs.meta | 11 + Runtime/Core/Animation/GraphicColorTo.cs | 64 +++ Runtime/Core/Animation/GraphicColorTo.cs.meta | 11 + Runtime/Core/Animation/RotateBy.cs | 8 + Runtime/Core/Animation/RotateBy.cs.meta | 11 + Runtime/Core/Animation/RotateTo.cs | 53 +++ Runtime/Core/Animation/RotateTo.cs.meta | 11 + Runtime/Core/Animation/ScaleBy.cs | 7 + Runtime/Core/Animation/ScaleBy.cs.meta | 11 + Runtime/Core/Animation/ScaleTo.cs | 53 +++ Runtime/Core/Animation/ScaleTo.cs.meta | 11 + .../Core/Animation/SpriteRendererAlphaTo.cs | 54 +++ .../Animation/SpriteRendererAlphaTo.cs.meta | 11 + .../Core/Animation/SpriteRendererColorTo.cs | 54 +++ .../Animation/SpriteRendererColorTo.cs.meta | 11 + Runtime/Core/Animation/TranslateBy.cs | 7 + Runtime/Core/Animation/TranslateBy.cs.meta | 11 + Runtime/Core/Animation/TranslateTo.cs | 73 ++++ Runtime/Core/Animation/TranslateTo.cs.meta | 11 + Runtime/Core/Easing.cs | 247 ++++++++++++ Runtime/Core/Easing.cs.meta | 11 + Runtime/Core/Event.meta | 8 + Runtime/Core/Event/UnityEventNode.cs | 12 + Runtime/Core/Event/UnityEventNode.cs.meta | 11 + Runtime/Core/Node.meta | 3 + Runtime/Core/Node/ActionNode.cs | 141 +++++++ Runtime/Core/Node/ActionNode.cs.meta | 3 + Runtime/Core/Node/Editor_ActionNode.cs | 17 + Runtime/Core/Node/Editor_ActionNode.cs.meta | 3 + Runtime/Core/Property.meta | 8 + Runtime/Core/Property/ButtonInteractable.cs | 35 ++ .../Core/Property/ButtonInteractable.cs.meta | 11 + Runtime/Core/Property/CanvasGroupProperty.cs | 59 +++ .../Core/Property/CanvasGroupProperty.cs.meta | 11 + Runtime/Core/Property/GameObjectActive.cs | 34 ++ .../Core/Property/GameObjectActive.cs.meta | 11 + Runtime/Core/Property/GraphicAlpha.cs | 36 ++ Runtime/Core/Property/GraphicAlpha.cs.meta | 11 + Runtime/Core/Property/GraphicColor.cs | 37 ++ Runtime/Core/Property/GraphicColor.cs.meta | 11 + Runtime/Core/Property/ImageSprite.cs | 37 ++ Runtime/Core/Property/ImageSprite.cs.meta | 11 + Runtime/Core/Property/SiblingIndex.cs | 35 ++ Runtime/Core/Property/SiblingIndex.cs.meta | 11 + .../Core/Property/SpriteRendererProperty.cs | 60 +++ .../Property/SpriteRendererProperty.cs.meta | 11 + Runtime/Core/Property/TransformProperty.cs | 59 +++ .../Core/Property/TransformProperty.cs.meta | 11 + Runtime/Core/Utility.meta | 8 + Runtime/Core/Utility/Delay.cs | 12 + Runtime/Core/Utility/Delay.cs.meta | 11 + .../Core/Utility/SequenceFrameAnimation.cs | 69 ++++ .../Utility/SequenceFrameAnimation.cs.meta | 11 + Runtime/Core/Utility/UnityDebug.cs | 18 + Runtime/Core/Utility/UnityDebug.cs.meta | 11 + Runtime/EAnimationFlowPlayebleType.cs | 12 + Runtime/EAnimationFlowPlayebleType.cs.meta | 3 + link.xml | 3 + link.xml.meta | 3 + package.json | 20 + package.json.meta | 7 + 113 files changed, 3841 insertions(+) create mode 100644 Editor.meta create mode 100644 Editor/AlicizaX.AnimationFlow.Editor.asmdef create mode 100644 Editor/AlicizaX.AnimationFlow.Editor.asmdef.meta create mode 100644 Editor/Data.meta create mode 100644 Editor/Data/AnimationFlowSerialize.cs create mode 100644 Editor/Data/AnimationFlowSerialize.cs.meta create mode 100644 Editor/Graph.meta create mode 100644 Editor/Graph/GraphView.cs create mode 100644 Editor/Graph/GraphView.cs.meta create mode 100644 Editor/Graph/NodeView.cs create mode 100644 Editor/Graph/NodeView.cs.meta create mode 100644 Editor/Graph/SearchWindowProvider.cs create mode 100644 Editor/Graph/SearchWindowProvider.cs.meta create mode 100644 Editor/Inspector.meta create mode 100644 Editor/Inspector/GraphInspector.cs create mode 100644 Editor/Inspector/GraphInspector.cs.meta create mode 100644 Editor/Misc.meta create mode 100644 Editor/Misc/EditorResourceTool.cs create mode 100644 Editor/Misc/EditorResourceTool.cs.meta create mode 100644 Editor/Styles.meta create mode 100644 Editor/Styles/AnimationFlowStyles.uss create mode 100644 Editor/Styles/AnimationFlowStyles.uss.meta create mode 100644 Editor/Styles/Complete.png create mode 100644 Editor/Styles/Complete.png.meta create mode 100644 Editor/Styles/SplitView.cs create mode 100644 Editor/Styles/SplitView.cs.meta create mode 100644 Editor/Styles/UICheckMark.png create mode 100644 Editor/Styles/UICheckMark.png.meta create mode 100644 Editor/Styles/UIGraphWindow.uxml create mode 100644 Editor/Styles/UIGraphWindow.uxml.meta create mode 100644 Editor/Styles/Warning.png create mode 100644 Editor/Styles/Warning.png.meta create mode 100644 Editor/Window.meta create mode 100644 Editor/Window/GraphWindow.cs create mode 100644 Editor/Window/GraphWindow.cs.meta create mode 100644 LICENSE.md create mode 100644 LICENSE.md.meta create mode 100644 Runtime.meta create mode 100644 Runtime/AlicizaX.AnimationFlow.Runtime.asmdef create mode 100644 Runtime/AlicizaX.AnimationFlow.Runtime.asmdef.meta create mode 100644 Runtime/AnimationFlow.cs create mode 100644 Runtime/AnimationFlow.cs.meta create mode 100644 Runtime/Attribute.meta create mode 100644 Runtime/Attribute/CategoryAttribute.cs create mode 100644 Runtime/Attribute/CategoryAttribute.cs.meta create mode 100644 Runtime/Attribute/NameAttribute.cs create mode 100644 Runtime/Attribute/NameAttribute.cs.meta create mode 100644 Runtime/Core.meta create mode 100644 Runtime/Core/Animation.meta create mode 100644 Runtime/Core/Animation/CanvasGroupAlphaTo.cs create mode 100644 Runtime/Core/Animation/CanvasGroupAlphaTo.cs.meta create mode 100644 Runtime/Core/Animation/GraphicAlphaTo.cs create mode 100644 Runtime/Core/Animation/GraphicAlphaTo.cs.meta create mode 100644 Runtime/Core/Animation/GraphicColorTo.cs create mode 100644 Runtime/Core/Animation/GraphicColorTo.cs.meta create mode 100644 Runtime/Core/Animation/RotateBy.cs create mode 100644 Runtime/Core/Animation/RotateBy.cs.meta create mode 100644 Runtime/Core/Animation/RotateTo.cs create mode 100644 Runtime/Core/Animation/RotateTo.cs.meta create mode 100644 Runtime/Core/Animation/ScaleBy.cs create mode 100644 Runtime/Core/Animation/ScaleBy.cs.meta create mode 100644 Runtime/Core/Animation/ScaleTo.cs create mode 100644 Runtime/Core/Animation/ScaleTo.cs.meta create mode 100644 Runtime/Core/Animation/SpriteRendererAlphaTo.cs create mode 100644 Runtime/Core/Animation/SpriteRendererAlphaTo.cs.meta create mode 100644 Runtime/Core/Animation/SpriteRendererColorTo.cs create mode 100644 Runtime/Core/Animation/SpriteRendererColorTo.cs.meta create mode 100644 Runtime/Core/Animation/TranslateBy.cs create mode 100644 Runtime/Core/Animation/TranslateBy.cs.meta create mode 100644 Runtime/Core/Animation/TranslateTo.cs create mode 100644 Runtime/Core/Animation/TranslateTo.cs.meta create mode 100644 Runtime/Core/Easing.cs create mode 100644 Runtime/Core/Easing.cs.meta create mode 100644 Runtime/Core/Event.meta create mode 100644 Runtime/Core/Event/UnityEventNode.cs create mode 100644 Runtime/Core/Event/UnityEventNode.cs.meta create mode 100644 Runtime/Core/Node.meta create mode 100644 Runtime/Core/Node/ActionNode.cs create mode 100644 Runtime/Core/Node/ActionNode.cs.meta create mode 100644 Runtime/Core/Node/Editor_ActionNode.cs create mode 100644 Runtime/Core/Node/Editor_ActionNode.cs.meta create mode 100644 Runtime/Core/Property.meta create mode 100644 Runtime/Core/Property/ButtonInteractable.cs create mode 100644 Runtime/Core/Property/ButtonInteractable.cs.meta create mode 100644 Runtime/Core/Property/CanvasGroupProperty.cs create mode 100644 Runtime/Core/Property/CanvasGroupProperty.cs.meta create mode 100644 Runtime/Core/Property/GameObjectActive.cs create mode 100644 Runtime/Core/Property/GameObjectActive.cs.meta create mode 100644 Runtime/Core/Property/GraphicAlpha.cs create mode 100644 Runtime/Core/Property/GraphicAlpha.cs.meta create mode 100644 Runtime/Core/Property/GraphicColor.cs create mode 100644 Runtime/Core/Property/GraphicColor.cs.meta create mode 100644 Runtime/Core/Property/ImageSprite.cs create mode 100644 Runtime/Core/Property/ImageSprite.cs.meta create mode 100644 Runtime/Core/Property/SiblingIndex.cs create mode 100644 Runtime/Core/Property/SiblingIndex.cs.meta create mode 100644 Runtime/Core/Property/SpriteRendererProperty.cs create mode 100644 Runtime/Core/Property/SpriteRendererProperty.cs.meta create mode 100644 Runtime/Core/Property/TransformProperty.cs create mode 100644 Runtime/Core/Property/TransformProperty.cs.meta create mode 100644 Runtime/Core/Utility.meta create mode 100644 Runtime/Core/Utility/Delay.cs create mode 100644 Runtime/Core/Utility/Delay.cs.meta create mode 100644 Runtime/Core/Utility/SequenceFrameAnimation.cs create mode 100644 Runtime/Core/Utility/SequenceFrameAnimation.cs.meta create mode 100644 Runtime/Core/Utility/UnityDebug.cs create mode 100644 Runtime/Core/Utility/UnityDebug.cs.meta create mode 100644 Runtime/EAnimationFlowPlayebleType.cs create mode 100644 Runtime/EAnimationFlowPlayebleType.cs.meta create mode 100644 link.xml create mode 100644 link.xml.meta create mode 100644 package.json create mode 100644 package.json.meta diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..b6d9c2a --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c8cb3e33a856dc4a99a3bbe94231fa9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AlicizaX.AnimationFlow.Editor.asmdef b/Editor/AlicizaX.AnimationFlow.Editor.asmdef new file mode 100644 index 0000000..9e7987b --- /dev/null +++ b/Editor/AlicizaX.AnimationFlow.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "AlicizaX.AnimationFlow.Editor", + "rootNamespace": "AlicizaX.AnimationFlow.Editor", + "references": [ + "GUID:189d55e03d78888459720d730f4d2424" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/AlicizaX.AnimationFlow.Editor.asmdef.meta b/Editor/AlicizaX.AnimationFlow.Editor.asmdef.meta new file mode 100644 index 0000000..fdd1899 --- /dev/null +++ b/Editor/AlicizaX.AnimationFlow.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: da025bffb2b9d1344b59cf03601655ea +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Data.meta b/Editor/Data.meta new file mode 100644 index 0000000..9c4a714 --- /dev/null +++ b/Editor/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc52eb5fc47d72342a352309fb3b7832 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Data/AnimationFlowSerialize.cs b/Editor/Data/AnimationFlowSerialize.cs new file mode 100644 index 0000000..b67cbde --- /dev/null +++ b/Editor/Data/AnimationFlowSerialize.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using AlicizaX.AnimationFlow.Runtime; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Editor { + public class AnimationFlowSerialize { + public string flag; + [SerializeReference] + public List nodes = new(); + } +} diff --git a/Editor/Data/AnimationFlowSerialize.cs.meta b/Editor/Data/AnimationFlowSerialize.cs.meta new file mode 100644 index 0000000..23b89ec --- /dev/null +++ b/Editor/Data/AnimationFlowSerialize.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4af60c68d7208084695e7fa37b683425 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Graph.meta b/Editor/Graph.meta new file mode 100644 index 0000000..b4a615c --- /dev/null +++ b/Editor/Graph.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10fd447a6852a0e42b41b454370606a2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Graph/GraphView.cs b/Editor/Graph/GraphView.cs new file mode 100644 index 0000000..72fc508 --- /dev/null +++ b/Editor/Graph/GraphView.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using AlicizaX.AnimationFlow.Runtime; +using UnityEditor; +using UnityEditor.Experimental.GraphView; +using UnityEngine; +using UnityEngine.UIElements; + +namespace AlicizaX.AnimationFlow.Editor +{ + public class GraphView : UnityEditor.Experimental.GraphView.GraphView + { + private readonly SearchWindowProvider searchWindowProvider; + private readonly GraphWindow graphWindow; + private readonly Dictionary dicNodeView = new(); + private Runtime.AnimationFlow animationFlow; + private const string applicationFlag = "@AnimationFlow"; + + private readonly Dictionary pendingNodes = new(); + + public GraphView(GraphWindow graphWindow) : base() + { + this.graphWindow = graphWindow; + InitView(); + SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale); + this.AddManipulator(new SelectionDragger()); + this.AddManipulator(new RectangleSelector()); + this.AddManipulator(new ContentDragger()); + + searchWindowProvider = ScriptableObject.CreateInstance(); + searchWindowProvider.Initialize(graphWindow, this); + + + SetCopyAndPaste(); + graphViewChanged += OnGraphViewChanged; + } + + + private void InitView() + { + this.StretchToParentSize(); + + Insert(0, new GridBackground()); + AddStyles(); + MiniMap miniMap = new(); + Add(miniMap); + miniMap.style.backgroundColor = new Color(0.12f, 0.12f, 0.12f, 1f); + miniMap.style.borderBottomColor = new Color(0.2f, 0.2f, 0.2f, 1f); + miniMap.style.borderRightColor = new Color(0.2f, 0.2f, 0.2f, 1f); + miniMap.style.borderTopColor = new Color(0.2f, 0.2f, 0.2f, 1f); + miniMap.style.borderLeftColor = new Color(0.2f, 0.2f, 0.2f, 1f); + } + + private void SetCopyAndPaste() + { + serializeGraphElements += (IEnumerable elements) => + { + AnimationFlowSerialize serialize = new(); + serialize.flag = applicationFlag; + foreach (var ele in elements) + { + if (ele is NodeView nodeView) + { + serialize.nodes.Add(nodeView.actionNode); + } + } + + return JsonUtility.ToJson(serialize); + }; + canPasteSerializedData += (string data) => { return data.Contains(applicationFlag); }; + unserializeAndPaste += (string operationName, string data) => + { + ClearSelection(); + Undo.RecordObject(animationFlow, operationName); + Vector2 mousePos = contentViewContainer.WorldToLocal(contentRect.center); + try + { + AnimationFlowSerialize serialize = JsonUtility.FromJson(data); + List newDatas = new(); + Dictionary dicUid = new(); + foreach (ActionNode node in serialize.nodes) + { + node.nodePos = node.nodePos + mousePos; + string uuid = node.uuid; + node.uuid = Guid.NewGuid().ToString(); + NodeView nodeView = AddNodeView(node); + AddToSelection(nodeView); + newDatas.Add(node); + dicUid.Add(uuid, node); + } + + foreach (ActionNode copyNode in newDatas) + { + for (int i = copyNode.Childs.Count - 1; i >= 0; i--) + { + if (dicUid.TryGetValue(copyNode.Childs[i].uuid, out ActionNode newNode)) + { + copyNode.Childs[i] = newNode; + if (dicNodeView.TryGetValue(copyNode.uuid, out NodeView inNode) && dicNodeView.TryGetValue(newNode.uuid, out NodeView outNode)) + { + AddElement(inNode.portOut.ConnectTo(outNode.portIn)); + } + } + else + { + copyNode.Childs.RemoveAt(i); + } + } + } + } + catch (Exception) + { + } + }; + } + + private void ResetEdge() + { + List nodes = new List(); + foreach (var item in animationFlow.AnimationNodes) + { + nodes.Add(item); + } + + List allNodes = new List(); + LoadAllChildNode(nodes, allNodes); + + + foreach (ActionNode data in allNodes) + { + foreach (ActionNode node in allNodes) + { + if (data.Childs.Count > 0 && data.Childs.Find(a => a.uuid == node.uuid) != null) + { + if (dicNodeView.TryGetValue(data.uuid, out NodeView inNode) && dicNodeView.TryGetValue(node.uuid, out NodeView outNode)) + { + AddElement(inNode.portOut.ConnectTo(outNode.portIn)); + } + } + } + } + } + + + private NodeView ResetNodeView(ActionNode data) + { + NodeView nodeView = new(data, graphWindow); + AddElement(nodeView); + nodeView.SetPosition(new Rect(data.nodePos, Vector2.zero)); + dicNodeView.Add(data.uuid, nodeView); + return nodeView; + } + + private void RemoveNodeView(NodeView nodeView) + { + dicNodeView.Remove(nodeView.actionNode.uuid); + pendingNodes.Remove(nodeView.actionNode.uuid); + if (nodeView.actionNode is EntryNode) + { + animationFlow.AnimationNodes.Remove(nodeView.actionNode as EntryNode); + } + } + + private void AddStyles() + { + StyleSheet styleSheet = AssetDatabase.LoadAssetAtPath(EditorResourceTool.editorAssets + "/AnimationFlowStyles.uss"); + styleSheets.Add(styleSheet); + } + + private GraphViewChange OnGraphViewChanged(GraphViewChange change) + { + change.edgesToCreate?.ForEach(edge => + { + if (animationFlow == null) + { + ClearGraph(); + return; + } + + Undo.RecordObject(animationFlow, "Create Edge"); + NodeView nodeIn = edge.input.node as NodeView; + NodeView nodeOut = edge.output.node as NodeView; + nodeOut.actionNode.Childs.Add(nodeIn.actionNode); + EditorUtility.SetDirty(animationFlow); + }); + + change.elementsToRemove?.ForEach(elem => + { + if (animationFlow == null) + { + ClearGraph(); + return; + } + + if (elem is Edge edge) + { + Undo.RecordObject(animationFlow, "Rmove Edge"); + NodeView nodeIn = edge.input.node as NodeView; + NodeView nodeOut = edge.output.node as NodeView; + nodeOut.actionNode.Childs.Remove(nodeIn.actionNode); + } + + if (elem is NodeView node) + { + Undo.RecordObject(animationFlow, "Remove Node"); + RemoveNodeView(node); + graphWindow.OnNodeRemove(); + } + + EditorUtility.SetDirty(animationFlow); + }); + change.movedElements?.ForEach(elem => + { + if (animationFlow == null) + { + ClearGraph(); + return; + } + + if (elem is NodeView nodeView) + { + Undo.RecordObject(animationFlow, "Move Node"); + nodeView.actionNode.nodePos = nodeView.GetPosition().position; + } + + EditorUtility.SetDirty(animationFlow); + }); + return change; + } + + public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) + { + SearchWindow.Open(new SearchWindowContext(GUIUtility.GUIToScreenPoint(evt.mousePosition)), searchWindowProvider); + } + + public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) + { + List compatiblePorts = new(); + ports.ForEach(port => + { + if (startPort == port) + { + return; + } + + if (startPort.node == port.node) + { + return; + } + + if (startPort.direction == port.direction) + { + return; + } + + if (startPort.portType != port.portType) + { + return; + } + + compatiblePorts.Add(port); + }); + + return compatiblePorts; + } + + protected override bool canDeleteSelection => base.canDeleteSelection && !Application.isPlaying && animationFlow != null && !animationFlow.InPlaying; + protected override bool canCopySelection => base.canCopySelection && !Application.isPlaying && animationFlow != null && !animationFlow.InPlaying; + protected override bool canCutSelection => base.canCutSelection && !Application.isPlaying && animationFlow != null && !animationFlow.InPlaying; + protected override bool canDuplicateSelection => base.canDuplicateSelection && !Application.isPlaying && animationFlow != null && !animationFlow.InPlaying; + protected override bool canPaste => base.canPaste && !Application.isPlaying && animationFlow != null; + + public NodeView AddNodeView(ActionNode node) + { + if (animationFlow == null) + { + return null; + } + + Undo.RecordObject(animationFlow, "Create Node"); + if (node is EntryNode) + { + animationFlow.AnimationNodes.Add(node as EntryNode); + } + else + { + pendingNodes.Add(node.uuid, node); + } + + return ResetNodeView(node); + } + + public void ClearGraph() + { + graphElements.ForEach(g => RemoveElement(g)); + dicNodeView.Clear(); + animationFlow = null; + } + + public void SetAnimationFlow(Runtime.AnimationFlow animationFlow) + { + this.animationFlow = animationFlow; + + List nodes = new List(); + foreach (var VARIABLE in animationFlow.AnimationNodes) + { + nodes.Add(VARIABLE); + } + + + List allNodes = new List(); + LoadAllChildNode(nodes, allNodes); + + foreach (ActionNode data in allNodes) + { + ResetNodeView(data); + } + + ResetEdge(); + } + + private void LoadAllChildNode(List nodes, List collector) + { + foreach (var item in nodes) + { + collector.Add(item); + if (item.Childs.Count > 0) LoadAllChildNode(item.Childs, collector); + } + } + + + public void ResetView() + { + foreach (NodeView nodeView in dicNodeView.Values) + { + nodeView.RemoveProgress(); + nodeView.RemoveComplete(); + } + } + + + public void OnNodeEnter(ActionNode actionNode) + { + if (dicNodeView.TryGetValue(actionNode.uuid, out NodeView nodeView)) + { + nodeView.AddProgress(); + } + } + + public void OnNodeExit(ActionNode actionNode) + { + if (dicNodeView.TryGetValue(actionNode.uuid, out NodeView nodeView)) + { + nodeView.RemoveProgress(); + nodeView.AddComplete(); + } + } + + public void OnNodeUpdate(ActionNode actionNode) + { + if (dicNodeView.TryGetValue(actionNode.uuid, out NodeView nodeView)) + { + nodeView.UpdateProgress(); + } + } + } +} \ No newline at end of file diff --git a/Editor/Graph/GraphView.cs.meta b/Editor/Graph/GraphView.cs.meta new file mode 100644 index 0000000..730b441 --- /dev/null +++ b/Editor/Graph/GraphView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58e6b0dfd8ab40e4b8854c0fd03a2fdf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Graph/NodeView.cs b/Editor/Graph/NodeView.cs new file mode 100644 index 0000000..0a3c1ad --- /dev/null +++ b/Editor/Graph/NodeView.cs @@ -0,0 +1,123 @@ +using System; +using System.Linq; +using AlicizaX.AnimationFlow.Runtime; +using UnityEditor; +using UnityEditor.Experimental.GraphView; +using UnityEngine; +using UnityEngine.UIElements; +using static UnityEditor.Experimental.GraphView.Port; + +namespace AlicizaX.AnimationFlow.Editor { + public class NodeView : Node { + public readonly ActionNode actionNode; + public Port portIn; + public Port portOut; + private readonly GraphWindow graphWindow; + private ProgressBar progressPlaying; + private Image imageComplete; + private Image imageWarning; + private Label sub_title; + + public NodeView(ActionNode node, GraphWindow graphWindow) { + this.actionNode = node; + this.graphWindow = graphWindow; + Draw(); + } + private void Draw() { + Type type = actionNode.GetType(); + NameAttribute nameAttribute = type.GetCustomAttributes(typeof(NameAttribute), true).FirstOrDefault() as NameAttribute; + title = nameAttribute != null && !string.IsNullOrEmpty(nameAttribute.name) ? nameAttribute.name : type.Name; + if (actionNode.HasInputPort()) { + portIn = InstantiatePort(Orientation.Horizontal, Direction.Input, actionNode.MultiInputPort() ? Capacity.Multi : Capacity.Single, typeof(bool)); + inputContainer.Add(portIn); + portIn.portName = "in"; + } + if (actionNode.HasOutPort()) { + portOut = InstantiatePort(Orientation.Horizontal, Direction.Output, actionNode.MultiOutPort() ? Capacity.Multi : Capacity.Single, typeof(bool)); + outputContainer.Add(portOut); + portOut.portName = "out"; + } + titleContainer.Remove(titleButtonContainer); + imageComplete = new() { + image = AssetDatabase.LoadAssetAtPath(EditorResourceTool.editorAssets + "/Complete.png"), + tintColor = new Color(0.4f, 0.7f, 0.2f), + style = { marginLeft = 3, marginRight = 10, visibility = Visibility.Hidden } + }; + titleContainer.Add(imageComplete); + + imageWarning = new() { + image = AssetDatabase.LoadAssetAtPath(EditorResourceTool.editorAssets + "/Warning.png"), + tintColor = Color.red, + style = { position = Position.Absolute, right = 0, top = 5 } + }; + titleContainer.Add(imageWarning); + + RefreshState(); + + if (actionNode.HasSubTitle()) { + sub_title = new(actionNode.SubTitle()) { + style = { fontSize = 12, paddingLeft = 8, paddingBottom = 5, backgroundColor = new Color(0.23f, 0.23f, 0.23f, 1f) } + }; + this.Q("node-border").Insert(1, sub_title); + } + this.Q("title").style.height = 25; + } + + public void RefreshState() { + imageWarning.style.visibility = actionNode.Valid() ? Visibility.Hidden : Visibility.Visible; + if (sub_title != null) { + if (string.IsNullOrEmpty(actionNode.SubTitle())) { + sub_title.text = ""; + sub_title.style.color = Color.red; + } else { + sub_title.text = actionNode.SubTitle(); + sub_title.style.color = new Color(0.82f, 0.82f, 0.82f, 1f); + } + } + } + + public void AddComplete() { + imageComplete.style.visibility = Visibility.Visible; + } + + public void RemoveComplete() { + imageComplete.style.visibility = Visibility.Hidden; + } + + public void AddProgress() { + if (actionNode.Duration() == 0) { + return; + } + progressPlaying = new(); + progressPlaying.style.height = 10; + contentContainer.Add(progressPlaying); + progressPlaying.highValue = actionNode.Duration(); + progressPlaying.value = 0; + RefreshExpandedState(); + } + + public void UpdateProgress() { + if (actionNode.Duration() == 0) { + return; + } + if (progressPlaying == null) { + AddProgress(); + } + progressPlaying.value = actionNode.elapsedTime; + } + + public void RemoveProgress() { + if (progressPlaying == null) { + return; + } + contentContainer.Remove(progressPlaying); + progressPlaying = null; + RefreshExpandedState(); + } + + public override void OnSelected() { + base.OnSelected(); + graphWindow.OnSelect(this); + } + } +} diff --git a/Editor/Graph/NodeView.cs.meta b/Editor/Graph/NodeView.cs.meta new file mode 100644 index 0000000..fc03420 --- /dev/null +++ b/Editor/Graph/NodeView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cdc2d2302b871c641bb2538b37280dbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Graph/SearchWindowProvider.cs b/Editor/Graph/SearchWindowProvider.cs new file mode 100644 index 0000000..ea402ef --- /dev/null +++ b/Editor/Graph/SearchWindowProvider.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AlicizaX.AnimationFlow.Runtime; +using UnityEditor.Experimental.GraphView; +using UnityEngine; +using UnityEngine.UIElements; + +namespace AlicizaX.AnimationFlow.Editor { + public class SearchWindowProvider : ScriptableObject, ISearchWindowProvider { + private GraphWindow graphWindow; + private GraphView graphView; + private Texture2D icon; + + public void Initialize(GraphWindow graphWindow, GraphView graphView) { + this.graphWindow = graphWindow; + this.graphView = graphView; + icon = new Texture2D(1, 1); + icon.SetPixel(0, 0, Color.clear); + icon.Apply(); + } + + List ISearchWindowProvider.CreateSearchTree(SearchWindowContext context) { + List entries = new() { + new SearchTreeGroupEntry(new GUIContent("Create Node",icon)) + }; + Dictionary> dicType = new(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { + foreach (var type in assembly.GetTypes()) { + if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(ActionNode))) { + CategoryAttribute categoryAttribute = type.GetCustomAttributes(typeof(CategoryAttribute), true).FirstOrDefault() as CategoryAttribute; + if (categoryAttribute == null || string.IsNullOrEmpty(categoryAttribute.category)) { + NameAttribute nameAttribute = type.GetCustomAttributes(typeof(NameAttribute), true).FirstOrDefault() as NameAttribute; + entries.Add(new SearchTreeEntry(new GUIContent(nameAttribute != null && !string.IsNullOrEmpty(nameAttribute.name) ? nameAttribute.name : type.Name, icon)) { level = 1, userData = type }); + } else { + if (dicType.TryGetValue(categoryAttribute.category, out var list)) { + list.Add(type); + } else { + dicType.Add(categoryAttribute.category, new List() { type }); + } + } + } + } + } + foreach (var kv in dicType) { + entries.Add(new SearchTreeGroupEntry(new GUIContent(kv.Key), 1)); + foreach (Type type in kv.Value) { + NameAttribute nameAttribute = type.GetCustomAttributes(typeof(NameAttribute), true).FirstOrDefault() as NameAttribute; + entries.Add(new SearchTreeEntry(new GUIContent(nameAttribute != null && !string.IsNullOrEmpty(nameAttribute.name) ? nameAttribute.name : type.Name, icon)) { level = 2, userData = type }); + } + } + return entries; + } + + bool ISearchWindowProvider.OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context) { + var type = searchTreeEntry.userData as Type; + var data = Activator.CreateInstance(type) as ActionNode; + data.uuid = Guid.NewGuid().ToString(); + data.nodePos = graphView.contentViewContainer.WorldToLocal(context.screenMousePosition - graphWindow.position.position); + graphView.AddNodeView(data); + return true; + } + } +} diff --git a/Editor/Graph/SearchWindowProvider.cs.meta b/Editor/Graph/SearchWindowProvider.cs.meta new file mode 100644 index 0000000..f13b323 --- /dev/null +++ b/Editor/Graph/SearchWindowProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d78888718c3f29e45a248128d078a137 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector.meta b/Editor/Inspector.meta new file mode 100644 index 0000000..6b894cf --- /dev/null +++ b/Editor/Inspector.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d6016243a18ef4b4896a29f8f4ebd99d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector/GraphInspector.cs b/Editor/Inspector/GraphInspector.cs new file mode 100644 index 0000000..77dfe7a --- /dev/null +++ b/Editor/Inspector/GraphInspector.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; +using AlicizaX.AnimationFlow.Runtime; +using Sirenix.OdinInspector.Editor; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace AlicizaX.AnimationFlow.Editor +{ + public class GraphInspector : VisualElement + { + private PropertyTree propertyTree; + + public void DrawNode(NodeView nodeView) + { + Clear(); + if (nodeView.actionNode == null) + { + return; + } + + // 使用 Odin PropertyTree 来处理非 UnityEngine.Object 对象 + propertyTree = PropertyTree.Create(nodeView.actionNode); + + var imguiContainer = new IMGUIContainer(() => + { + if (propertyTree == null) + { + return; + } + + propertyTree.Draw(false); + // 手动调用 Odin 的 Apply,处理数据更新后的逻辑 + if (propertyTree.ApplyChanges()) + { + nodeView.RefreshState(); + } + }); + + Add(imguiContainer); + propertyTree.Dispose(); + } + } +} \ No newline at end of file diff --git a/Editor/Inspector/GraphInspector.cs.meta b/Editor/Inspector/GraphInspector.cs.meta new file mode 100644 index 0000000..2241d5e --- /dev/null +++ b/Editor/Inspector/GraphInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3354982c2d9e304da519e305e3a88ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Misc.meta b/Editor/Misc.meta new file mode 100644 index 0000000..1d439a8 --- /dev/null +++ b/Editor/Misc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 70212f83948d68d49a038353c5c292e7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Misc/EditorResourceTool.cs b/Editor/Misc/EditorResourceTool.cs new file mode 100644 index 0000000..098bf11 --- /dev/null +++ b/Editor/Misc/EditorResourceTool.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Editor { + public static class EditorResourceTool { + public static string editorAssets; + + public static bool LocateEditorAssets() { + string projectPath = Application.dataPath; + if (projectPath.EndsWith("/Assets")) { + projectPath = projectPath.Remove(projectPath.Length - ("Assets".Length)); + } + editorAssets = "Packages/com.yuliuren.alicizaframework/ThirdParty/AnimationFlow/Editor/Styles"; + if (!System.IO.File.Exists(projectPath + editorAssets + "/AnimationFlowStyles.uss")) { + var sdir = new System.IO.DirectoryInfo(Application.dataPath); + var dirQueue = new Queue(); + dirQueue.Enqueue(sdir); + bool found = false; + while (dirQueue.Count > 0) { + System.IO.DirectoryInfo dir = dirQueue.Dequeue(); + if (System.IO.File.Exists(dir.FullName + "/AnimationFlowStyles.uss")) { + string path = dir.FullName.Replace('\\', '/'); + found = true; + path = path.Replace(projectPath, ""); + if (path.StartsWith("/")) { + path = path.Remove(0, 1); + } + editorAssets = path; + return true; + } + var dirs = dir.GetDirectories(); + for (int i = 0; i < dirs.Length; i++) { + dirQueue.Enqueue(dirs[i]); + } + } + if (!found) { + Debug.LogWarning("Could not locate editor assets folder. Make sure you have imported the package correctly."); + return false; + } + } + return true; + } + } +} diff --git a/Editor/Misc/EditorResourceTool.cs.meta b/Editor/Misc/EditorResourceTool.cs.meta new file mode 100644 index 0000000..322902c --- /dev/null +++ b/Editor/Misc/EditorResourceTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7a3682890e722b41b230347c29487d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Styles.meta b/Editor/Styles.meta new file mode 100644 index 0000000..86e56ea --- /dev/null +++ b/Editor/Styles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc7e58d5bf8127246b4ef1945c0d9140 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Styles/AnimationFlowStyles.uss b/Editor/Styles/AnimationFlowStyles.uss new file mode 100644 index 0000000..8f18996 --- /dev/null +++ b/Editor/Styles/AnimationFlowStyles.uss @@ -0,0 +1,7 @@ +GridBackground +{ + --grid-background-color:#2b2b2b; + --line-color:rgba(55,55,55,1); + --thick-line-color:rgba(55,55,55,1); + --spacing:40; +} \ No newline at end of file diff --git a/Editor/Styles/AnimationFlowStyles.uss.meta b/Editor/Styles/AnimationFlowStyles.uss.meta new file mode 100644 index 0000000..0a2ae87 --- /dev/null +++ b/Editor/Styles/AnimationFlowStyles.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f82e3630fa0ecb41b029ea6ce3a5cbb +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Editor/Styles/Complete.png b/Editor/Styles/Complete.png new file mode 100644 index 0000000000000000000000000000000000000000..4043ee9809fbc057b15fbdb5a57343f3cc00153e GIT binary patch literal 18328 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 { } + } +} \ No newline at end of file diff --git a/Editor/Styles/SplitView.cs.meta b/Editor/Styles/SplitView.cs.meta new file mode 100644 index 0000000..27c836d --- /dev/null +++ b/Editor/Styles/SplitView.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a794fdf26eb8e9c4aac599b04c03fa37 +timeCreated: 1675978413 \ No newline at end of file diff --git a/Editor/Styles/UICheckMark.png b/Editor/Styles/UICheckMark.png new file mode 100644 index 0000000000000000000000000000000000000000..7799d32b4e9573494230ab4de70ba133bc1c08ad GIT binary patch literal 973 zcmaJ=O^ee&7!EGT+O;4k_;DJtu(*rOB>m3NxMZ8wEtpce#r7g@noPH0H<_4BH|e4m zJ$V%`UIdTA;#I+eCl7*%;>|y>H$ClnophV72Wwz5A3V?VzVp7%JZm-Yq*FIi9LJ>_ zn_8RAOYvAd&;D-?!xc7Nr?np4A_E#4KIT-5^f72S#tv>{!x}&Qj4K?suwr+5w5Q)i zCUFEK#t4z)F*e6l)+5g_cQFNhykolx|NFy79@v(`cMH0xdsRHNHxGQgb4FewsAm4zR4OlSdK$^sOn>b62C*pUQ)%@kWdl~i3h6H zxN0SEvunE+34_%MN7qrq4XELoxS=ULQxR<2Lb4t8n6wa&QZx!l+ej>jTv*thqwRriSlCf7#x{9Foi^`=~FelEqiT*#7v zadZD_c5=iV6fbAiWt*A#vCACqGi!H`!3*{*l!m5uqMwJ~)f6W#E~r0FPR7bHzqXn` zGSn-Vel;s!KE1#8?$PVD!PEOMFWfs!?_=FVtp~53pS#F?+g`f-_3F{%_<=QQP3`T* G_LD!2>n)i8 literal 0 HcmV?d00001 diff --git a/Editor/Styles/UICheckMark.png.meta b/Editor/Styles/UICheckMark.png.meta new file mode 100644 index 0000000..4908a1f --- /dev/null +++ b/Editor/Styles/UICheckMark.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 3a8e09bf61f38fe42beb76e9adc5921d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 0 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + swizzle: 50462976 + cookieLightType: 1 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 1 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 1 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Styles/UIGraphWindow.uxml b/Editor/Styles/UIGraphWindow.uxml new file mode 100644 index 0000000..abf8693 --- /dev/null +++ b/Editor/Styles/UIGraphWindow.uxml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Editor/Styles/UIGraphWindow.uxml.meta b/Editor/Styles/UIGraphWindow.uxml.meta new file mode 100644 index 0000000..93d4cdb --- /dev/null +++ b/Editor/Styles/UIGraphWindow.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 43465dc65d73bca49a224ece1d2b91d8 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Editor/Styles/Warning.png b/Editor/Styles/Warning.png new file mode 100644 index 0000000000000000000000000000000000000000..77b6da620cdc40d8beddc0f40f1ed2276e9ade4a GIT binary patch literal 20513 zcmeI4c~n!$(!ehRvV*&*h!YkCk?aYO7=jR1*#v?F_bfLdLKc%Ki^_ls;xZzlf*=g) zC<=-TiXy0piaUtAf}jE-`oK4$gQEiPhUF3vXEJYQzIVQJ!a0zlZ&h{oudA!8?;lw| z+t=MdccLx;00y2OE&gTNC<=H(zN5edvfiLZkqoH(LIy2BhyA4*U=` z>`;+RBn=gb5uP*}LM#z+`Qab{L_Wz3KfHq)_c*~tK6G??fDgw6mCRnFPq z3NSFh7_QeP67UEKU_67l9>CF4KxxGYz2ktkK7jF0jGqQ*tN<2YH8+n0*6swxxV;Oe z{4za%M3Xf{YUgoEkp;;$Zk{%Bsa9|>YO+;@r_uB=w#@IC=`&GfQ9CE#;t0c^wcP}O z?Bub~Y}+~_D-821Dr`3w8ZJVV^|F_>Z{!{yKJz4y-TWlDO)O{Qx_e8}n0o(F zOETEu%Q|pMp(Ir&170Jj03)t$vdRdNO$Vy+d1Hijt z(S>_f+Ul{PYo1p|biH-#aL=9s#Bx2iE(L&vE*2>I^#aE$+5q5^9cO*i$@u++@iwKJ zlP(OaxuExDvF%!Ci%VtBBb;?Pv6Cc=ryW}DY?W~9sEPGr^u3uTgi`;|gcPwMsx0WV zp@Vq%C#H7R1*?)c9Sx_e+M}7KPZHHw8yM!BwT*Vhe>A<|p)qQs1>#!b7=JUbWTFQ) zU;`Zy`5|ajn}Pz1tiaHa%%v zcE)YViHQ!IYB#BD9f+>A9UJHLI9D^#q=zPrHMkj@R!KkFs=n*RtX_xFQMy;peEQ_{$=XvaB`khgC-0lbi%$scvW)M6k znx|ZQ!U;RBMcQVAn0__BA+zCP1HQqy!Svlc-AvZZr9XcRd|?%EeaWl|jUyTfjhbK@ z&M9bbdce~IyXhl|NpqbK?=B2D;=k^|Xu`5|(ycY)JiYcE-n0Gg#89KqcK(r9vNI!} zZlCO%dOP^ejb`^(sjt-EN9Y?Qj9qgjk!Lj_W4zXQ-h_zpN7B6aPq@2r!WBBk4*Mpp zY3J~rq9BHKq4mnK$=7wa&)Pn9yRkKzelT}`Zf&k!P+QOqdeXs#fvfV}g7AU$2X*f4 z$P3ENoc$)yIFNU6#({OYyaOV-<1U%6PLowmYFo^P z+A(jZy_jaapWt1D1?Pw5?nvFi$n(ha&vSos);7N-Cv*Q<*W!@RafVJ;W?9a+bmt{i z49jc^d>r^RM>l7jj|2HbJ}NhCpYiTumx%MioYu6ga|>g$yhS;+QD>VzO@a_i=;J+~h0BxX2ZAL5!anlc_{ z)SX&9H*&5`;eo=_py%<1x%)#}3rmFYb4ell7(sIv6u2GEJUrz=@!{f}kvT=aDZY7G z4|o@k{!)0Y@ZhNlM;jk$R_7NA3Rf|CEF<2j%lQ{uQ_iNWI4hJoRb&n16Oy-)z zNKZ({kmrzV(<^qhIen&H!$EX}p`3PTMIQqu4OZ?2hjJxhUBVLhoO;KL7(p4u0Y+s=GzME#X2`Kg{-PqC}T)rKs( zX;*sc>Zu!k7e!f%;_GNXn0IlyqPwbqoY*O9JoWW)PI2?T`}{F_rRn+2j^t|a*W-^{ zoHk__IgNEnT77tRZ1!cFd~>x3!ornHw+0=v&6Giw{n4 z+$>IHOsvAD5+kZ=Xwo{DPcA!LYBP9PKhhE8ETT0v7qx`)#O@5?jAJ>98*=kLBa`77 z?lp;ovd*^^hM%kZ($co>Mdk~=`V~fL=&K9FQM)V3-pA*RJBS)(L*6mdJJHvE+rOPg zSRWX-Y0A6N5mPqnMwOYA@yyUwwpEFbX!ETn`@ZwA_KDv5ujCS9l*MKIKAXm(wU!6B zlz1C>Kg}R#jZ0sS5a1lhXR&LxCU05loNMZnQpkJFd&ymX;}95syz{bf<0>V!-lZZ=CHD@u`DHCKYo6hb+|-w;hC+kKPfi%r%{kHX;aAscbm}du>f$wpw4%M| zDW^-ooNE=gW;oJ+roX3uqT9CKd3uuh@T0J*)p$k8uY`Zyubx-Z-a)-~t~y99$mc%y zKKR-5b3waf{`%bJk2^jK7992!EN!`>en-7S%iOT=VbQ(&CU+d@0Z9+0zi~Ib^8LBa z%(oFp16zZjA9t0%Fc-T-H8i*D)U{7GAU|2YX~m)ET6e!+Zo)G`FL6$Pm+qDknErVl zYu*{Zo7AcYuWO^fxL1Ead>4Td5;d!hevSX6dG*~C-n+_8ncFj0#h`wxSzNuRa77cl zqHf7>(c3d4WY6!oc5Q5$Q8J@q{=3t%cgL$6M+ct{PCr6kBzP@*P3cUz>vyGiS8;lN z(fqKY*66b*S8&^#jkD}3p1waD^~<=f2lul`4o}avMT^=mw|}S`_cTUg*->$$_;G|~ z>){f=l11-lwm3beJzaO-ab9Q5qqj9bEGdo1ZmX(sZ`X`pQ`wpPA!#^mSklg<8wmyp zZ?f#EB+?50d00`ER<%3zU24jC!ODFduS?%d zI8t3+RzCUMwMaa6;rltCTP{S@M3}tYTQ}UVVI|@RtFF-Bj(rHco%1~hs_6c2|xa3$IzPi_zZ2_ zH(r5Y$gZU_*X0m`UZexM?X#59qr@OO0F;WBN!Xz4a%d{%L(N_)3jq69M+sMu`jC!f zeC{{=$e(-@0vO5vhMD|Hk6Cw2^(-|7f<~rEK&DJ2p^HS})ShtdzlcHiFsop`kRyta zPNSd)Yxl=Yza!9vDFdlcOcRh891?3!#}LRwJ2DnK9Rme7M!`vs<{%$FA`YJ$rQidP z#AE4@DV9hk5~pMEunz^z!9Jip$YIKuN_kP#Rq(@Mler>^fGMN$1xy}@77KY4bbq6Q zCLEb$nkZZ(frbTA@f7q>%|lv2ciq`NS6!+!z}*?)=}NQ3l5A~}I22aVje_2ge&}GN z%$penN~8)43@vka_HbtM2DbJ+2hwLeo%9uhn=;=a*8c=*bhfLyd?bu8X5owRXV~|Wd0g~7xdnAVm5^QZbws2=M4T!WBfdyvUNa)@>~B*-O@kSsP6kHlf@Ko;cL9>lQw zTq~G=<=RiehiV6AxPp#+^nbRCA>4e`l?Pu6CF-bwJD_`i2ZBonw*I&KyZbC8GuiU` zfXbGi3?PSs9?;r9tp0u7qrm@q0hOctmHD^(hzJFRzjwU!xa!vWwiBs{D~n)CKqnp) z6Mt~%^*9`8G1&9po11!i>|Fy6DB&;v6KeovawsRu& z#I{G`>}~BxY!*}<5bgS=s9-*Lith1F#lkn{^do(5eZlh&YpxMurX{TmPBA7Nh}Ty$pxXcV-sv~ z91^i_et&k+hO8o0i`Jha`oQ*PoxyR_A8HC2p*ySmK_Zdo8aVOvb)w*7a7X`Ofc|}% z^#9MC|MI3(t^n)VNvchW=n3C})mUE<`E~WySDf}7@ow@%T7JiYw#Oe_#-LLPdT~Hj z0Nz(HE1N_InGe{8z1}(hZOz;>I0f^eyo>&7+1%615N`T=>m%>d4_Ki}rpVu}uOwMjSIdUJ&IG~s2=D=b=qUgYy9NM$ z>w-R;0bm&h0A4Q!0CE}t7>Twny6gt&vOHa!=#fuYU%I*+)rURPS65$yO;6KNSHBn{ zG2pPW^-C-RHVF;)khAYOwI_}-E;4("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(); + } + } +} diff --git a/Editor/Window/GraphWindow.cs.meta b/Editor/Window/GraphWindow.cs.meta new file mode 100644 index 0000000..7d90781 --- /dev/null +++ b/Editor/Window/GraphWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b445b46064d2e84695eb2caba51708f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4e6513a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [2023] [ALianBlank of copyright owner][alianblank@outlook.com][https://alianblank.com/] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE.md.meta b/LICENSE.md.meta new file mode 100644 index 0000000..5385af2 --- /dev/null +++ b/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5a68ca6cac9f6bf4d879d41d6eed3744 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..7b6cefc --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 464232d91c91b1848bdf08d6249dbf7e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef b/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef new file mode 100644 index 0000000..794feed --- /dev/null +++ b/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef @@ -0,0 +1,14 @@ +{ + "name": "AlicizaX.AnimationFlow.Runtime", + "rootNamespace": "AlicizaX.AnimationFlow.Runtime", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef.meta b/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef.meta new file mode 100644 index 0000000..9abeedb --- /dev/null +++ b/Runtime/AlicizaX.AnimationFlow.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 189d55e03d78888459720d730f4d2424 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AnimationFlow.cs b/Runtime/AnimationFlow.cs new file mode 100644 index 0000000..f60d34b --- /dev/null +++ b/Runtime/AnimationFlow.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Sirenix.OdinInspector; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime +{ + public class AnimationFlow : MonoBehaviour + { + #region Editor相关 + +#if UNITY_EDITOR + IEnumerable GetAllAnimationClips + { + get + { + List keys = new(); + foreach (EntryNode root in AnimationNodes) + { + if (!string.IsNullOrEmpty(root.Name)) + { + keys.Add(root.Name); + } + } + + keys.Insert(0, "None"); + return keys; + } + } + + [Button("节点编辑器", ButtonSizes.Large), GUIColor(0, 1, 0)] + private void OpenGraphWindow() + { + UnityEditor.EditorApplication.ExecuteMenuItem("AlicizaFramework/Window/AnimationGraph"); + } +#endif + + #endregion + + [HideInInspector] [SerializeReference] public List AnimationNodes = new List(); + + + [LabelText("动画片段")] [BoxGroup("基础设置", true)] [ValueDropdown("GetAllAnimationClips", ExpandAllMenuItems = true)] [SerializeField] + private string _defaultPlayName = "None"; + + [LabelText("自动播放")] [BoxGroup("基础设置", true)] [SerializeField] + private bool _enableAutoPlay; + + + private List _runningNodes = new List(); + + private List _resetNodes = new List(); + + private ActionNode _curEntryNode; + + private int _loopCount = 0; + + /// + /// 节点播放回调 + /// + private Action _playFinishEvent; + + /// + /// 时间缩放系数 受Time.deltatime影响 + /// + private float _timeScale = 1f; + + public float TimeScale + { + get => _timeScale; + set => _timeScale = value; + } + + /// + /// 当前节点状态 + /// + private EAnimationFlowPlayebleType _playebleType = EAnimationFlowPlayebleType.Stop; + + public EAnimationFlowPlayebleType AnimationFlowPlayebleType + { + get => _playebleType; + set => _playebleType = value; + } + + + /// + /// 是否播放中 + /// + public bool InPlaying => _playebleType == EAnimationFlowPlayebleType.Play; + + /// + /// 是否暂停中 + /// + public bool InPause => _playebleType == EAnimationFlowPlayebleType.Pause; + + + private void Start() + { + if (_enableAutoPlay) + { + Play(_defaultPlayName); + } + } + + private void Update() + { + if (_playebleType == EAnimationFlowPlayebleType.Play) + { + Tick(Time.deltaTime * _timeScale); + } + } + + + public void Tick(float deltaTime) + { + List runNodes = _runningNodes; + int runCount = runNodes.Count; + if (runCount == 0) + { + if (_loopCount > 0) + { + _loopCount--; + ResetNode(); + PushNode(_curEntryNode); + } + else + { + StopFlow(); + } + } + + if (runCount > 0) + { + for (int i = runCount - 1; i >= 0; i--) + { + ActionNode node = _runningNodes[i]; + if (node.Condition()) + { + PopNode(node); + } + else + { + node.elapsedTime = Mathf.Min(node.elapsedTime + deltaTime, node.Duration()); + node.OnUpdate(deltaTime); + node.State = EState.Running; + } + } + } + } + + + public void ResetNode() + { + for (int i = _resetNodes.Count - 1; i >= 0; i--) + { + ActionNode node = _resetNodes[i]; + node.Reset(); + node.OnReset(); + } + + _resetNodes.Clear(); + } + + private void StopFlow(bool isInterrupt = false) + { + _playebleType = EAnimationFlowPlayebleType.Stop; + _curEntryNode = null; + _loopCount = 0; + for (int i = _resetNodes.Count - 1; i >= 0; i--) + { + ActionNode node = _resetNodes[i]; + if (!Application.isPlaying) + { + node.OnReset(); + } + + node.Reset(); + } + + if (isInterrupt) + { + for (int i = _runningNodes.Count - 1; i >= 0; i--) + { + ActionNode node = _runningNodes[i]; + node.OnInterrupt(); + } + } + + if (_playFinishEvent != null) _playFinishEvent(); + + _resetNodes.Clear(); + _runningNodes.Clear(); + } + + private void PopNode(ActionNode node) + { + node.OnExit(); + node.State = EState.Exit; + _runningNodes.Remove(node); + PushChildNode(node); + } + + private void PushChildNode(ActionNode node) + { + List childNode = node.Childs; + if (childNode.Count > 0) + { + foreach (var child in childNode) + { + PushNode(child); + } + } + } + + private void PushNode(ActionNode node) + { + node.OnInit(); + node.OnEnter(); + node.State = EState.Enter; + _runningNodes.Add(node); + _resetNodes.Add(node); + } + + + public void Play(string clipName = "", Action actionComplete = null) + { + if (_playebleType == EAnimationFlowPlayebleType.Play) + { + Debug.LogWarning($"animation flow is playing!"); + return; + } + + if (string.IsNullOrEmpty(clipName) || clipName == "None") + { + Debug.LogWarning($"animation name is empty!"); + return; + } + + _playFinishEvent = actionComplete; + + EntryNode entryNode = AnimationNodes.Find(a => a.Name == clipName); + if (entryNode == null) + { + Debug.LogWarning($"Can not find this Clip {clipName}!"); + return; + } + + + _loopCount = entryNode.LoopCount; + _curEntryNode = entryNode; + _playebleType = EAnimationFlowPlayebleType.Play; + } + + + public void Stop() + { + if (_playebleType == EAnimationFlowPlayebleType.Play) + { + StopFlow(true); + } + } + } +} diff --git a/Runtime/AnimationFlow.cs.meta b/Runtime/AnimationFlow.cs.meta new file mode 100644 index 0000000..a93a1ce --- /dev/null +++ b/Runtime/AnimationFlow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7859f2b76d69e044b4e966f48a3607d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Attribute.meta b/Runtime/Attribute.meta new file mode 100644 index 0000000..48a44e9 --- /dev/null +++ b/Runtime/Attribute.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eb9425389d58394438e9c298fb1be473 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Attribute/CategoryAttribute.cs b/Runtime/Attribute/CategoryAttribute.cs new file mode 100644 index 0000000..f08663d --- /dev/null +++ b/Runtime/Attribute/CategoryAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Diagnostics; + +namespace AlicizaX.AnimationFlow.Runtime { + [AttributeUsage(AttributeTargets.Class), Conditional("UNITY_EDITOR")] + public class CategoryAttribute : Attribute { + public readonly string category; + public CategoryAttribute(string category) { + this.category = category; + } + } +} diff --git a/Runtime/Attribute/CategoryAttribute.cs.meta b/Runtime/Attribute/CategoryAttribute.cs.meta new file mode 100644 index 0000000..bcb9707 --- /dev/null +++ b/Runtime/Attribute/CategoryAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c802bbbb85f92b46b9b8b25b7c60c6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Attribute/NameAttribute.cs b/Runtime/Attribute/NameAttribute.cs new file mode 100644 index 0000000..7b22da5 --- /dev/null +++ b/Runtime/Attribute/NameAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Diagnostics; + +namespace AlicizaX.AnimationFlow.Runtime { + [AttributeUsage(AttributeTargets.Class), Conditional("UNITY_EDITOR")] + public class NameAttribute : Attribute { + public readonly string name; + public NameAttribute(string name) { + this.name = name; + } + } +} diff --git a/Runtime/Attribute/NameAttribute.cs.meta b/Runtime/Attribute/NameAttribute.cs.meta new file mode 100644 index 0000000..0ef5fa7 --- /dev/null +++ b/Runtime/Attribute/NameAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 778aaafb0861e3c4db400e4c33dc196d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core.meta b/Runtime/Core.meta new file mode 100644 index 0000000..5ec4103 --- /dev/null +++ b/Runtime/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c6e796f19ed1b846af619435694f84c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation.meta b/Runtime/Core/Animation.meta new file mode 100644 index 0000000..3f54b31 --- /dev/null +++ b/Runtime/Core/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: db4c0b464a82e5e41a5f34e2c8d16103 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/CanvasGroupAlphaTo.cs b/Runtime/Core/Animation/CanvasGroupAlphaTo.cs new file mode 100644 index 0000000..b745e28 --- /dev/null +++ b/Runtime/Core/Animation/CanvasGroupAlphaTo.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class CanvasGroupAlphaTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public CanvasGroup target; + public bool setFrom; + public float from; + public float to; + + protected float orgValue; + protected float enterValue; + + public override void OnInit() + { + orgValue = target.alpha; + } + + public override void OnReset() + { + target.alpha = orgValue; + } + + public override void OnEnter() { + if (setFrom) { + target.alpha = from; + } + enterValue = target.alpha; + } + + public override void OnUpdate(float dt) { + target.alpha = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} + diff --git a/Runtime/Core/Animation/CanvasGroupAlphaTo.cs.meta b/Runtime/Core/Animation/CanvasGroupAlphaTo.cs.meta new file mode 100644 index 0000000..e5f7ee1 --- /dev/null +++ b/Runtime/Core/Animation/CanvasGroupAlphaTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c82daf623932c3345bf323b8896cb8ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/GraphicAlphaTo.cs b/Runtime/Core/Animation/GraphicAlphaTo.cs new file mode 100644 index 0000000..cf37b66 --- /dev/null +++ b/Runtime/Core/Animation/GraphicAlphaTo.cs @@ -0,0 +1,54 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class GraphicAlphaTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public Graphic target; + public bool setFrom; + public float from; + public float to; + + protected float orgValue; + protected float enterValue; + + public override void OnInit() { + orgValue = target.color.a; + } + + public override void OnReset() { + target.color = new Color(target.color.r, target.color.g, target.color.b, orgValue); + } + + public override void OnEnter() { + if (setFrom) { + target.color = new Color(target.color.r, target.color.g, target.color.b, from); + } + enterValue = target.color.a; + } + + public override void OnUpdate(float dt) { + float a = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + target.color = new Color(target.color.r, target.color.g, target.color.b, a); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} + diff --git a/Runtime/Core/Animation/GraphicAlphaTo.cs.meta b/Runtime/Core/Animation/GraphicAlphaTo.cs.meta new file mode 100644 index 0000000..7d096c4 --- /dev/null +++ b/Runtime/Core/Animation/GraphicAlphaTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f361b6d0dd63444c90c7cf04cf4f1c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/GraphicColorTo.cs b/Runtime/Core/Animation/GraphicColorTo.cs new file mode 100644 index 0000000..33ebf1b --- /dev/null +++ b/Runtime/Core/Animation/GraphicColorTo.cs @@ -0,0 +1,64 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime +{ + [Category("Animation")] + public class GraphicColorTo : ActionNode + { + public float duration = 1f; + public EaseType easyType; + public Graphic target; + public bool setFrom; + public Color from = Color.white; + public Color to = Color.white; + + protected Color orgValue; + protected Color enterValue; + + public override void OnInit() + { + orgValue = target.color; + } + + public override void OnReset() + { + target.color = orgValue; + } + + public override void OnEnter() + { + if (setFrom) + { + target.color = from; + } + + enterValue = target.color; + } + + public override void OnUpdate(float dt) + { + target.color = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() + { + return target != null && duration > 0; + } + + public override float Duration() + { + return duration; + } + + public override bool HasSubTitle() + { + return true; + } + + public override string SubTitle() + { + return target != null ? target.name : null; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Animation/GraphicColorTo.cs.meta b/Runtime/Core/Animation/GraphicColorTo.cs.meta new file mode 100644 index 0000000..116863d --- /dev/null +++ b/Runtime/Core/Animation/GraphicColorTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9836fe491e0a4314fa94efc524735925 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/RotateBy.cs b/Runtime/Core/Animation/RotateBy.cs new file mode 100644 index 0000000..ac8fd18 --- /dev/null +++ b/Runtime/Core/Animation/RotateBy.cs @@ -0,0 +1,8 @@ +namespace AlicizaX.AnimationFlow.Runtime { + public class RotateBy : RotateTo { + public override void OnUpdate(float dt) { + target.localEulerAngles = Easing.Ease(easyType, enterValue, enterValue + to, elapsedTime / duration); + } + } +} + diff --git a/Runtime/Core/Animation/RotateBy.cs.meta b/Runtime/Core/Animation/RotateBy.cs.meta new file mode 100644 index 0000000..2930c54 --- /dev/null +++ b/Runtime/Core/Animation/RotateBy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cce6a734565f484fba643dc361d3474 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/RotateTo.cs b/Runtime/Core/Animation/RotateTo.cs new file mode 100644 index 0000000..85d2690 --- /dev/null +++ b/Runtime/Core/Animation/RotateTo.cs @@ -0,0 +1,53 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class RotateTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public Transform target; + public bool setFrom; + public Vector3 from; + public Vector3 to; + + protected Vector3 orgValue; + protected Vector3 enterValue; + + public override void OnInit() { + orgValue = target.localEulerAngles; + } + + + public override void OnReset() { + target.localEulerAngles = orgValue; + } + + public override void OnEnter() { + if (setFrom) { + target.localEulerAngles = from; + } + enterValue = target.localEulerAngles; + } + + public override void OnUpdate(float dt) { + target.localEulerAngles = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} + diff --git a/Runtime/Core/Animation/RotateTo.cs.meta b/Runtime/Core/Animation/RotateTo.cs.meta new file mode 100644 index 0000000..c03e70d --- /dev/null +++ b/Runtime/Core/Animation/RotateTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18a73287c11ce7940943c0bd25a874a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/ScaleBy.cs b/Runtime/Core/Animation/ScaleBy.cs new file mode 100644 index 0000000..da218b4 --- /dev/null +++ b/Runtime/Core/Animation/ScaleBy.cs @@ -0,0 +1,7 @@ +namespace AlicizaX.AnimationFlow.Runtime { + public class ScaleBy : ScaleTo { + public override void OnUpdate(float dt) { + target.localScale = Easing.Ease(easyType, enterValue, enterValue + to, elapsedTime / duration); + } + } +} diff --git a/Runtime/Core/Animation/ScaleBy.cs.meta b/Runtime/Core/Animation/ScaleBy.cs.meta new file mode 100644 index 0000000..40417a9 --- /dev/null +++ b/Runtime/Core/Animation/ScaleBy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f2109b4e7936fa4daa936c16631d872 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/ScaleTo.cs b/Runtime/Core/Animation/ScaleTo.cs new file mode 100644 index 0000000..235f2a5 --- /dev/null +++ b/Runtime/Core/Animation/ScaleTo.cs @@ -0,0 +1,53 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class ScaleTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public Transform target; + public bool setFrom; + public Vector3 from; + public Vector3 to = Vector3.one; + + protected Vector3 orgValue; + protected Vector3 enterValue; + + public override void OnInit() { + orgValue = target.localScale; + } + + + + public override void OnReset() { + target.localScale = orgValue; + } + + public override void OnEnter() { + if (setFrom) { + target.localScale = from; + } + enterValue = target.localScale; + } + + public override void OnUpdate(float dt) { + target.localScale = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Animation/ScaleTo.cs.meta b/Runtime/Core/Animation/ScaleTo.cs.meta new file mode 100644 index 0000000..1682051 --- /dev/null +++ b/Runtime/Core/Animation/ScaleTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef75f4b0af6091c44a0e5379ce730cab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/SpriteRendererAlphaTo.cs b/Runtime/Core/Animation/SpriteRendererAlphaTo.cs new file mode 100644 index 0000000..e13c5f1 --- /dev/null +++ b/Runtime/Core/Animation/SpriteRendererAlphaTo.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class SpriteRendererAlphaTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public SpriteRenderer target; + public bool setFrom; + public float from; + public float to; + + protected float orgValue; + protected float enterValue; + + public override void OnInit() { + orgValue = target.color.a; + } + + + public override void OnReset() { + target.color = new Color(target.color.r, target.color.g, target.color.b, orgValue); + } + + public override void OnEnter() { + if (setFrom) { + target.color = target.color = new Color(target.color.r, target.color.g, target.color.b, from); + } + enterValue = target.color.a; + } + + public override void OnUpdate(float dt) { + float a = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + target.color = new Color(target.color.r, target.color.g, target.color.b, a); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} + diff --git a/Runtime/Core/Animation/SpriteRendererAlphaTo.cs.meta b/Runtime/Core/Animation/SpriteRendererAlphaTo.cs.meta new file mode 100644 index 0000000..a171a79 --- /dev/null +++ b/Runtime/Core/Animation/SpriteRendererAlphaTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9842477ac251bf42b93cc7b38b013e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/SpriteRendererColorTo.cs b/Runtime/Core/Animation/SpriteRendererColorTo.cs new file mode 100644 index 0000000..52023db --- /dev/null +++ b/Runtime/Core/Animation/SpriteRendererColorTo.cs @@ -0,0 +1,54 @@ +using UnityEngine; + + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Animation")] + public class SpriteRendererColorTo : ActionNode { + public float duration = 1f; + public EaseType easyType; + public SpriteRenderer target; + public bool setFrom; + public Color from = Color.white; + public Color to = Color.white; + + protected Color orgValue; + protected Color enterValue; + + public override void OnInit() { + orgValue = target.color; + } + + + public override void OnReset() { + target.color = orgValue; + } + + public override void OnEnter() { + if (setFrom) { + target.color = from; + } + enterValue = target.color; + } + + public override void OnUpdate(float dt) { + target.color = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() { + return target != null && duration > 0; + } + + public override float Duration() { + return duration; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} + diff --git a/Runtime/Core/Animation/SpriteRendererColorTo.cs.meta b/Runtime/Core/Animation/SpriteRendererColorTo.cs.meta new file mode 100644 index 0000000..f5a68f7 --- /dev/null +++ b/Runtime/Core/Animation/SpriteRendererColorTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1327afe74b192734d89e2c8e5ba59bbc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/TranslateBy.cs b/Runtime/Core/Animation/TranslateBy.cs new file mode 100644 index 0000000..4ca71cc --- /dev/null +++ b/Runtime/Core/Animation/TranslateBy.cs @@ -0,0 +1,7 @@ +namespace AlicizaX.AnimationFlow.Runtime { + public class TranslateBy : TranslateTo { + public override void OnUpdate(float dt) { + target.localPosition = Easing.Ease(easyType, enterValue, enterValue + to, elapsedTime / duration); + } + } +} diff --git a/Runtime/Core/Animation/TranslateBy.cs.meta b/Runtime/Core/Animation/TranslateBy.cs.meta new file mode 100644 index 0000000..ed340bb --- /dev/null +++ b/Runtime/Core/Animation/TranslateBy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7c3f97c4ace7b949b5474584965ebbc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Animation/TranslateTo.cs b/Runtime/Core/Animation/TranslateTo.cs new file mode 100644 index 0000000..8cd1005 --- /dev/null +++ b/Runtime/Core/Animation/TranslateTo.cs @@ -0,0 +1,73 @@ +using Sirenix.OdinInspector; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime +{ + [Category("Animation")] + [System.Serializable] + public class TranslateTo : ActionNode + { + [LabelText("持续时间")] public float duration = 1f; + [LabelText("过渡类型")] public EaseType easyType; + + [ChildGameObjectsOnly] [LabelText("对象")] + public Transform target; + + [LabelText("设置起点")] public bool setFrom; + + [LabelText("开始")] [ShowIf("setFrom", true)] + public Vector3 from; + + [LabelText("结束")] public Vector3 to; + + protected Vector3 orgValue; + protected Vector3 enterValue; + + public override void OnInit() + { + orgValue = target.localPosition; + } + + + public override void OnReset() + { + target.localPosition = orgValue; + } + + public override void OnEnter() + { + if (setFrom) + { + target.localPosition = from; + } + + enterValue = target.localPosition; + } + + public override void OnUpdate(float dt) + { + target.localPosition = Easing.Ease(easyType, enterValue, to, elapsedTime / duration); + } + + public override bool Valid() + { + Debug.Log(target != null && duration > 0); + return target != null && duration > 0; + } + + public override float Duration() + { + return duration; + } + + public override bool HasSubTitle() + { + return true; + } + + public override string SubTitle() + { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Animation/TranslateTo.cs.meta b/Runtime/Core/Animation/TranslateTo.cs.meta new file mode 100644 index 0000000..641ffdc --- /dev/null +++ b/Runtime/Core/Animation/TranslateTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f8df2f2b18ba1045acda62e9de6944e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Easing.cs b/Runtime/Core/Easing.cs new file mode 100644 index 0000000..427524a --- /dev/null +++ b/Runtime/Core/Easing.cs @@ -0,0 +1,247 @@ +using System; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + public enum EaseType { + Linear, + QuadraticIn, + QuadraticOut, + QuadraticInOut, + QuarticIn, + QuarticOut, + QuarticInOut, + QuinticIn, + QuinticOut, + QuinticInOut, + CubicIn, + CubicOut, + CubicInOut, + ExponentialIn, + ExponentialOut, + ExponentialInOut, + CircularIn, + CircularOut, + CircularInOut, + SinusoidalIn, + SinusoidalOut, + SinusoidalInOut, + ElasticIn, + ElasticOut, + ElasticInOut, + BounceIn, + BounceOut, + BounceInOut, + BackIn, + BackOut, + BackInOut + } + + public static class Easing { + public static float Ease(EaseType type, float from, float to, float t) { + if (t <= 0) { return from; } + if (t >= 1) { return to; } + return Mathf.LerpUnclamped(from, to, Function(type)(t)); + } + + public static Vector3 Ease(EaseType type, Vector3 from, Vector3 to, float t) { + if (t <= 0) { return from; } + if (t >= 1) { return to; } + return Vector3.LerpUnclamped(from, to, Function(type)(t)); + } + + public static Quaternion Ease(EaseType type, Quaternion from, Quaternion to, float t) { + if (t <= 0) { return from; } + if (t >= 1) { return to; } + return Quaternion.LerpUnclamped(from, to, Function(type)(t)); + } + + public static Color Ease(EaseType type, Color from, Color to, float t) { + if (t <= 0) { return from; } + if (t >= 1) { return to; } + return Color.LerpUnclamped(from, to, Function(type)(t)); + } + + public static Func Function(EaseType type) { + return type switch { + EaseType.Linear => Linear, + EaseType.QuadraticIn => QuadraticIn, + EaseType.QuadraticOut => QuadraticOut, + EaseType.QuadraticInOut => QuadraticInOut, + EaseType.QuarticIn => QuarticIn, + EaseType.QuarticOut => QuarticOut, + EaseType.QuarticInOut => QuarticInOut, + EaseType.QuinticIn => QuinticIn, + EaseType.QuinticOut => QuinticOut, + EaseType.QuinticInOut => QuinticInOut, + EaseType.CubicIn => CubicIn, + EaseType.CubicOut => CubicOut, + EaseType.CubicInOut => CubicInOut, + EaseType.ExponentialIn => ExponentialIn, + EaseType.ExponentialOut => ExponentialOut, + EaseType.ExponentialInOut => ExponentialInOut, + EaseType.CircularIn => CircularIn, + EaseType.CircularOut => CircularOut, + EaseType.CircularInOut => CircularInOut, + EaseType.SinusoidalIn => SinusoidalIn, + EaseType.SinusoidalOut => SinusoidalOut, + EaseType.SinusoidalInOut => SinusoidalInOut, + EaseType.ElasticIn => ElasticIn, + EaseType.ElasticOut => ElasticOut, + EaseType.ElasticInOut => ElasticInOut, + EaseType.BounceIn => BounceIn, + EaseType.BounceOut => BounceOut, + EaseType.BounceInOut => BounceInOut, + EaseType.BackIn => BackIn, + EaseType.BackOut => BackOut, + EaseType.BackInOut => BackInOut, + _ => throw new ArgumentOutOfRangeException(), + }; + } + + public static float Linear(float t) { + return t; + } + + public static float QuadraticIn(float t) { + return t * t; + } + + public static float QuadraticOut(float t) { + return 1f - (1f - t) * (1f - t); + } + + public static float QuadraticInOut(float t) { + return t < 0.5f ? 2f * t * t : 1f - Mathf.Pow(-2f * t + 2f, 2f) / 2f; + } + + public static float QuarticIn(float t) { + return t * t * t * t; + } + + public static float QuarticOut(float t) { + return 1f - (--t * t * t * t); + } + + public static float QuarticInOut(float t) { + if ((t *= 2f) < 1f) + return 0.5f * t * t * t * t; + return -0.5f * ((t -= 2f) * t * t * t - 2f); + } + + public static float QuinticIn(float t) { + return t * t * t * t * t; + } + + public static float QuinticOut(float t) { + return --t * t * t * t * t + 1f; + } + + public static float QuinticInOut(float t) { + if ((t *= 2f) < 1) + return 0.5f * t * t * t * t * t; + return 0.5f * ((t -= 2f) * t * t * t * t + 2f); + } + + public static float CubicIn(float t) { + return t * t * t; + } + + public static float CubicOut(float t) { + return --t * t * t + 1f; + } + + public static float CubicInOut(float t) { + return t < 0.5 ? 4f * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 3f) / 2f; + } + + public static float SinusoidalIn(float t) { + return 1f - Mathf.Cos(t * Mathf.PI / 2f); + } + + public static float SinusoidalOut(float t) { + return Mathf.Sin(t * Mathf.PI / 2f); + } + + public static float SinusoidalInOut(float t) { + return 0.5f * (1f - Mathf.Cos(Mathf.PI * t)); + } + + public static float ExponentialIn(float t) { + return t == 0f ? 0f : Mathf.Pow(2f, 10f * t - 10f); + } + + public static float ExponentialOut(float t) { + return t == 1f ? 1f : 1f - Mathf.Pow(2f, -10f * t); + } + + public static float ExponentialInOut(float t) { + return t < 0.5f ? Mathf.Pow(2f, 20f * t - 10f) / 2f : (2f - Mathf.Pow(2f, -20f * t + 10f)) / 2f; + } + + public static float CircularIn(float t) { + return 1f - Mathf.Sqrt(1f - t * t); + } + + public static float CircularOut(float t) { + return Mathf.Sqrt(1f - (--t * t)); + } + + public static float CircularInOut(float t) { + return t < 0.5f ? (Mathf.Sqrt(1f - t * t) - 1f) / 2 : (Mathf.Sqrt(1f - (t -= 2f) * t) + 1f) / 2; + } + + public static float ElasticIn(float t) { + float x = (2f * Mathf.PI) / 3f; + return -Mathf.Pow(2f, 10f * t - 10f) * Mathf.Sin((t * 10f - 10.75f) * x); + } + + public static float ElasticOut(float t) { + float x = (2f * Mathf.PI) / 3f; + return Mathf.Pow(2f, -10f * t) * Mathf.Sin((t * 10f - 0.75f) * x) + 1f; + } + + public static float ElasticInOut(float t) { + float x = (2f * Mathf.PI) / 4.5f; + if (t < 0.5f) + return -(Mathf.Pow(2f, 20f * t - 10f) * Mathf.Sin((20f * t - 11.125f) * x)) / 2f; + return (Mathf.Pow(2f, -20f * t + 10f) * Mathf.Sin((20f * t - 11.125f) * x)) / 2f + 1f; + } + + public static float BounceIn(float t) { + return 1f - BounceOut(1f - t); + } + + public static float BounceOut(float t) { + if (t < (1f / 2.75f)) { + return 7.5625f * t * t; + } else if (t < (2f / 2.75f)) { + return 7.5625f * (t -= (1.5f / 2.75f)) * t + 0.75f; + } else if (t < (2.5f / 2.75f)) { + return 7.5625f * (t -= (2.25f / 2.75f)) * t + 0.9375f; + } else { + return 7.5625f * (t -= (2.625f / 2.75f)) * t + 0.984375f; + } + } + + public static float BounceInOut(float t) { + return t < 0.5f ? BounceIn(t * 2f) * 0.5f : BounceOut(t * 2f - 1f) * 0.5f + 0.5f; + } + + public static float BackIn(float t) { + float s = 1.70158f; + return t * t * ((s + 1f) * t - s); + } + + public static float BackOut(float t) { + float s = 1.70158f; + return --t * t * ((s + 1f) * t + s) + 1f; + } + + public static float BackInOut(float t) { + float s = 1.70158f * 1.525f; + if ((t *= 2f) < 1f) + return 0.5f * (t * t * ((s + 1) * t - s)); + return 0.5f * ((t -= 2f) * t * ((s + 1f) * t + s) + 2f); + } + } +} diff --git a/Runtime/Core/Easing.cs.meta b/Runtime/Core/Easing.cs.meta new file mode 100644 index 0000000..b990e6d --- /dev/null +++ b/Runtime/Core/Easing.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89bfa9261b873cf4aba9ca58ccb40156 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Event.meta b/Runtime/Core/Event.meta new file mode 100644 index 0000000..7f3aade --- /dev/null +++ b/Runtime/Core/Event.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2410b6af4b749be48adc490e6c1f24a3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Event/UnityEventNode.cs b/Runtime/Core/Event/UnityEventNode.cs new file mode 100644 index 0000000..30124c0 --- /dev/null +++ b/Runtime/Core/Event/UnityEventNode.cs @@ -0,0 +1,12 @@ +using UnityEngine.Events; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Event"), Name("UnityEvent")] + public class UnityEventNode : ActionNode { + public UnityEvent unityEvent; + + public override void OnEnter() { + unityEvent?.Invoke(); + } + } +} diff --git a/Runtime/Core/Event/UnityEventNode.cs.meta b/Runtime/Core/Event/UnityEventNode.cs.meta new file mode 100644 index 0000000..e646e73 --- /dev/null +++ b/Runtime/Core/Event/UnityEventNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fd856bb9f217e04c8f200ff54477a9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Node.meta b/Runtime/Core/Node.meta new file mode 100644 index 0000000..1677f68 --- /dev/null +++ b/Runtime/Core/Node.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2bd5293bdf6fd52439390bafec491b0e +timeCreated: 1731292591 \ No newline at end of file diff --git a/Runtime/Core/Node/ActionNode.cs b/Runtime/Core/Node/ActionNode.cs new file mode 100644 index 0000000..f50e587 --- /dev/null +++ b/Runtime/Core/Node/ActionNode.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using Sirenix.OdinInspector; +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime +{ + public enum EState + { + None, + Enter, + Running, + Exit, + } + + + [System.Serializable] + public class EntryNode : ActionNode + { + [LabelText("循环次数")] public int LoopCount = 1; // 控制流程循环的次数 + [LabelText("入口名称")] public string Name; // 节点名称(可以是技能名称、关卡名称等) + } + + [System.Serializable] + public abstract partial class ActionNode + { + [HideInInspector] public float elapsedTime; + + [HideInInspector] [SerializeReference] [SerializeField] + public List Childs = new List(); // 邻接节点(图中的边) + + [HideInInspector] public EState State; + + + /// + /// 该类型是否允许接受输入口 + /// + /// + public virtual bool HasInputPort() + { + return true; + } + + /// + /// 是否有多输入口 + /// + /// + public virtual bool MultiInputPort() + { + return true; + } + + /// + /// 是否有输出口 + /// + /// + public virtual bool HasOutPort() + { + return true; + } + + /// + /// 是否有多输出口 + /// + /// + public virtual bool MultiOutPort() + { + return true; + } + + /// + /// 持续时间 + /// + /// + public virtual float Duration() + { + return 0; + } + + /// + /// 前置条件 如果满足 则进入下一分支 + /// + /// + public virtual bool Condition() + { + return elapsedTime >= Duration(); + } + + public virtual bool HasSubTitle() + { + return false; + } + + public virtual string SubTitle() + { + return null; + } + + /// + /// 效验通过 编辑器使用 + /// + /// + public virtual bool Valid() + { + return true; + } + + + public virtual void OnInit() + { + } + + public virtual void OnEnter() + { + } + + public virtual void OnExit() + { + } + + public virtual void OnUpdate(float dt) + { + } + + + public virtual void OnInterrupt() + { + } + + public virtual void OnReset() + { + } + + public void Reset() + { + elapsedTime = 0; + State = EState.None; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Node/ActionNode.cs.meta b/Runtime/Core/Node/ActionNode.cs.meta new file mode 100644 index 0000000..5375b86 --- /dev/null +++ b/Runtime/Core/Node/ActionNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1329507424583a6498dd62a900edaf76 +timeCreated: 1731065028 \ No newline at end of file diff --git a/Runtime/Core/Node/Editor_ActionNode.cs b/Runtime/Core/Node/Editor_ActionNode.cs new file mode 100644 index 0000000..07c73a9 --- /dev/null +++ b/Runtime/Core/Node/Editor_ActionNode.cs @@ -0,0 +1,17 @@ + + +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime +{ +#if UNITY_EDITOR + public abstract partial class ActionNode + { + [HideInInspector] + public Vector2 nodePos; //GraphView使用 + [HideInInspector] + public string uuid; //GraphView映射的Id + } + +#endif +} \ No newline at end of file diff --git a/Runtime/Core/Node/Editor_ActionNode.cs.meta b/Runtime/Core/Node/Editor_ActionNode.cs.meta new file mode 100644 index 0000000..54c7fa8 --- /dev/null +++ b/Runtime/Core/Node/Editor_ActionNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b3a49f0f1e2c1e942a472ab2d6574c10 +timeCreated: 1731292612 \ No newline at end of file diff --git a/Runtime/Core/Property.meta b/Runtime/Core/Property.meta new file mode 100644 index 0000000..0d91dc7 --- /dev/null +++ b/Runtime/Core/Property.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1be47789456052f48b22caa8b33648f0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/ButtonInteractable.cs b/Runtime/Core/Property/ButtonInteractable.cs new file mode 100644 index 0000000..fa5c9f0 --- /dev/null +++ b/Runtime/Core/Property/ButtonInteractable.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class ButtonInteractable : ActionNode { + public Button target; + public bool interactable; + protected bool orgValue; + + public override void OnInit() { + orgValue = target.interactable; + } + + public override void OnReset() { + target.interactable = orgValue; + } + + public override void OnEnter() { + target.interactable = interactable; + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/ButtonInteractable.cs.meta b/Runtime/Core/Property/ButtonInteractable.cs.meta new file mode 100644 index 0000000..51acc6d --- /dev/null +++ b/Runtime/Core/Property/ButtonInteractable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c130e3aa2d1ba24f8efb203c21341ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/CanvasGroupProperty.cs b/Runtime/Core/Property/CanvasGroupProperty.cs new file mode 100644 index 0000000..fc9da44 --- /dev/null +++ b/Runtime/Core/Property/CanvasGroupProperty.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property"), Name("CanvasGroup")] + public class CanvasGroupProperty : ActionNode { + public CanvasGroup target; + public bool setAlpha = true; + public float alpha; + public bool setInteractable; + public bool interactable; + public bool setBlocksRaycasts; + public bool blocksRaycasts; + private float orgAlpha; + private bool orgInteractable; + private bool orgBlocksRaycasts; + + public override void OnInit() { + orgAlpha = target.alpha; + orgInteractable = target.interactable; + orgBlocksRaycasts = target.blocksRaycasts; + } + + public override void OnReset() { + if (setAlpha) { + target.alpha = orgAlpha; + } + if (setInteractable) { + target.interactable = orgInteractable; + } + if (setBlocksRaycasts) { + target.blocksRaycasts = orgBlocksRaycasts; + } + } + + public override void OnEnter() { + if (setAlpha) { + target.alpha = alpha; + } + if (setInteractable) { + target.interactable = interactable; + } + if (setBlocksRaycasts) { + target.blocksRaycasts = blocksRaycasts; + } + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/CanvasGroupProperty.cs.meta b/Runtime/Core/Property/CanvasGroupProperty.cs.meta new file mode 100644 index 0000000..b006eb6 --- /dev/null +++ b/Runtime/Core/Property/CanvasGroupProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4faaec8fb78ccc548a66ab12ef17783f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/GameObjectActive.cs b/Runtime/Core/Property/GameObjectActive.cs new file mode 100644 index 0000000..e2750e1 --- /dev/null +++ b/Runtime/Core/Property/GameObjectActive.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class GameObjectActive : ActionNode { + public GameObject target; + public bool active; + protected bool orgValue; + + public override void OnInit() { + orgValue = target.activeSelf; + } + + public override void OnReset() { + target.SetActive(orgValue); + } + + public override void OnEnter() { + target.SetActive(active); + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/GameObjectActive.cs.meta b/Runtime/Core/Property/GameObjectActive.cs.meta new file mode 100644 index 0000000..922100b --- /dev/null +++ b/Runtime/Core/Property/GameObjectActive.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d42bfaaa1c095e048918365a2f3961cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/GraphicAlpha.cs b/Runtime/Core/Property/GraphicAlpha.cs new file mode 100644 index 0000000..757a240 --- /dev/null +++ b/Runtime/Core/Property/GraphicAlpha.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class GraphicAlpha : ActionNode { + public Graphic target; + public float alpha; + + protected float orgValue; + + public override void OnInit() { + orgValue = target.color.a; + } + + public override void OnReset() { + target.color = new Color(target.color.r, target.color.g, target.color.b, orgValue); + } + + public override void OnEnter() { + target.color = new Color(target.color.r, target.color.g, target.color.b, alpha); + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/GraphicAlpha.cs.meta b/Runtime/Core/Property/GraphicAlpha.cs.meta new file mode 100644 index 0000000..4bc8e78 --- /dev/null +++ b/Runtime/Core/Property/GraphicAlpha.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26999d2beaeb18045ad1f3876b739644 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/GraphicColor.cs b/Runtime/Core/Property/GraphicColor.cs new file mode 100644 index 0000000..a9d087e --- /dev/null +++ b/Runtime/Core/Property/GraphicColor.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class GraphicColor : ActionNode { + public Graphic target; + public Color color = Color.white; + + protected Color orgValue; + + public override void OnInit() { + orgValue = target.color; + } + + + public override void OnReset() { + target.color = orgValue; + } + + public override void OnEnter() { + target.color = color; + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/GraphicColor.cs.meta b/Runtime/Core/Property/GraphicColor.cs.meta new file mode 100644 index 0000000..6dddfff --- /dev/null +++ b/Runtime/Core/Property/GraphicColor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ced79fffdfa1e94b80381771318ee16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/ImageSprite.cs b/Runtime/Core/Property/ImageSprite.cs new file mode 100644 index 0000000..a3e1521 --- /dev/null +++ b/Runtime/Core/Property/ImageSprite.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class ImageSprite : ActionNode { + public Image target; + public Sprite sprite; + + protected Sprite orgValue; + + public override void OnInit() { + orgValue = target.sprite; + } + + + public override void OnReset() { + target.sprite = orgValue; + } + + public override void OnEnter() { + target.sprite = sprite; + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/ImageSprite.cs.meta b/Runtime/Core/Property/ImageSprite.cs.meta new file mode 100644 index 0000000..28debbc --- /dev/null +++ b/Runtime/Core/Property/ImageSprite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2383f65101b8be4db8b58ae723f96aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/SiblingIndex.cs b/Runtime/Core/Property/SiblingIndex.cs new file mode 100644 index 0000000..9e47065 --- /dev/null +++ b/Runtime/Core/Property/SiblingIndex.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class SiblingIndex : ActionNode { + public Transform target; + public int index; + + protected int orgIndex; + + public override void OnInit() { + orgIndex = target.GetSiblingIndex(); + } + + public override void OnReset() { + target.SetSiblingIndex(orgIndex); + } + + public override void OnEnter() { + target.SetSiblingIndex(index); + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/SiblingIndex.cs.meta b/Runtime/Core/Property/SiblingIndex.cs.meta new file mode 100644 index 0000000..6f1a55c --- /dev/null +++ b/Runtime/Core/Property/SiblingIndex.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3810a3c63fa8e64d8b1506ef2c5bdd3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/SpriteRendererProperty.cs b/Runtime/Core/Property/SpriteRendererProperty.cs new file mode 100644 index 0000000..716425b --- /dev/null +++ b/Runtime/Core/Property/SpriteRendererProperty.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property")] + public class SpriteRendererProperty : ActionNode { + public SpriteRenderer target; + public bool setSprite = true; + public Sprite sprite; + public bool setColor; + public Color color; + public bool setLayer; + public int layer; + + protected Sprite orgSprite; + protected Color orgColor; + protected int orgLayer; + + public override void OnInit() { + orgSprite = target.sprite; + orgColor = target.color; + orgLayer = target.sortingLayerID; + } + + public override void OnReset() { + if (setSprite) { + target.sprite = orgSprite; + } + if (setColor) { + target.color = orgColor; + } + if (setLayer) { + target.sortingLayerID = orgLayer; + } + } + + public override void OnEnter() { + if (setSprite) { + target.sprite = sprite; + } + if (setColor) { + target.color = color; + } + if (setLayer) { + target.sortingLayerID = layer; + } + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/SpriteRendererProperty.cs.meta b/Runtime/Core/Property/SpriteRendererProperty.cs.meta new file mode 100644 index 0000000..87b4868 --- /dev/null +++ b/Runtime/Core/Property/SpriteRendererProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73e269ad4e3d1fb4d8f7ed4a84d09d9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Property/TransformProperty.cs b/Runtime/Core/Property/TransformProperty.cs new file mode 100644 index 0000000..06a8e3d --- /dev/null +++ b/Runtime/Core/Property/TransformProperty.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Property"), Name("Transform")] + public class TransformProperty : ActionNode { + public Transform target; + public bool setPosition = true; + public Vector3 position; + public bool setScale; + public Vector3 scale; + public bool setRotation; + public Vector3 rotation; + private Vector3 orgPosition; + private Vector3 orgScale; + private Vector3 orgRotation; + + public override void OnInit() { + orgPosition = target.localPosition; + orgScale = target.localScale; + orgRotation = target.eulerAngles; + } + + public override void OnReset() { + if (setPosition) { + target.localPosition = orgPosition; + } + if (setScale) { + target.localScale = orgScale; + } + if (setRotation) { + target.eulerAngles = orgRotation; + } + } + + public override void OnEnter() { + if (setPosition) { + target.localPosition = position; + } + if (setScale) { + target.localScale = scale; + } + if (setRotation) { + target.eulerAngles = rotation; + } + } + + public override bool Valid() { + return target != null; + } + + public override bool HasSubTitle() { + return true; + } + + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Property/TransformProperty.cs.meta b/Runtime/Core/Property/TransformProperty.cs.meta new file mode 100644 index 0000000..309b52b --- /dev/null +++ b/Runtime/Core/Property/TransformProperty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 96fe9eab07c128340890e3acf79a9ca7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility.meta b/Runtime/Core/Utility.meta new file mode 100644 index 0000000..6619699 --- /dev/null +++ b/Runtime/Core/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1489e270f4ddb2045a9389a4c8d1be23 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility/Delay.cs b/Runtime/Core/Utility/Delay.cs new file mode 100644 index 0000000..801f847 --- /dev/null +++ b/Runtime/Core/Utility/Delay.cs @@ -0,0 +1,12 @@ +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Utility")] + public class Delay : ActionNode { + public float duration; + public override float Duration() { + return duration; + } + public override bool Valid() { + return duration > 0; + } + } +} diff --git a/Runtime/Core/Utility/Delay.cs.meta b/Runtime/Core/Utility/Delay.cs.meta new file mode 100644 index 0000000..7e37f1e --- /dev/null +++ b/Runtime/Core/Utility/Delay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d827c7cbe5514c4a8d3e42f8971393b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility/SequenceFrameAnimation.cs b/Runtime/Core/Utility/SequenceFrameAnimation.cs new file mode 100644 index 0000000..0916900 --- /dev/null +++ b/Runtime/Core/Utility/SequenceFrameAnimation.cs @@ -0,0 +1,69 @@ + +using UnityEngine; + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Utility")] + public class SequenceFrameAnimation : ActionNode { + public SpriteRenderer target; + public float interval; + public Sprite[] sprites; + public bool rewind; + + private int curIndex; + private bool is_rewind; + private float curTime; + + private void ResetData() { + curIndex = 0; + is_rewind = false; + curTime = 0; + } + + public override void OnReset() { + ResetData(); + } + + public override void OnEnter() { + ResetData(); + } + + public override void OnUpdate(float dt) { + if (curTime <= 0) { + curTime += interval; + if (curIndex >= sprites.Length) { + return; + } + target.sprite = sprites[curIndex]; + if (is_rewind) { + curIndex = Mathf.Max(0, curIndex - 1); + } else { + curIndex++; + if (curIndex >= sprites.Length) { + if (rewind) { + is_rewind = true; + curIndex--; + } else { + curIndex = 0; + } + } + } + } else { + curTime -= dt; + } + } + + public override float Duration() { + return interval * (sprites.Length + 1) * (rewind ? 2 : 1); + } + + public override bool Valid() { + return interval > 0 && sprites.Length > 0; + } + public override bool HasSubTitle() { + return true; + } + public override string SubTitle() { + return target != null ? target.name : null; + } + } +} diff --git a/Runtime/Core/Utility/SequenceFrameAnimation.cs.meta b/Runtime/Core/Utility/SequenceFrameAnimation.cs.meta new file mode 100644 index 0000000..cf88b16 --- /dev/null +++ b/Runtime/Core/Utility/SequenceFrameAnimation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f63cdc1478cd3d4297fee3758c16d9c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility/UnityDebug.cs b/Runtime/Core/Utility/UnityDebug.cs new file mode 100644 index 0000000..4466c11 --- /dev/null +++ b/Runtime/Core/Utility/UnityDebug.cs @@ -0,0 +1,18 @@ + +namespace AlicizaX.AnimationFlow.Runtime { + [Category("Utility"), Name("Debug")] + public class UnityDebug : ActionNode { + public string value; + public override void OnEnter() { + UnityEngine.Debug.Log(value); + } + + public override bool Valid() { + return !string.IsNullOrEmpty(value); + } + + public override bool HasOutPort() { + return false; + } + } +} diff --git a/Runtime/Core/Utility/UnityDebug.cs.meta b/Runtime/Core/Utility/UnityDebug.cs.meta new file mode 100644 index 0000000..08764b6 --- /dev/null +++ b/Runtime/Core/Utility/UnityDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80f45b7db1b02c04eaafb2b132fa9d79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/EAnimationFlowPlayebleType.cs b/Runtime/EAnimationFlowPlayebleType.cs new file mode 100644 index 0000000..9b876df --- /dev/null +++ b/Runtime/EAnimationFlowPlayebleType.cs @@ -0,0 +1,12 @@ +namespace AlicizaX.AnimationFlow.Runtime +{ + /// + /// 动画节点状态 + /// + public enum EAnimationFlowPlayebleType + { + Play, + Pause, + Stop + } +} diff --git a/Runtime/EAnimationFlowPlayebleType.cs.meta b/Runtime/EAnimationFlowPlayebleType.cs.meta new file mode 100644 index 0000000..d52242f --- /dev/null +++ b/Runtime/EAnimationFlowPlayebleType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bd9b3c1b6a4375e408e55d73864e98e0 +timeCreated: 1730973371 \ No newline at end of file diff --git a/link.xml b/link.xml new file mode 100644 index 0000000..ded33a6 --- /dev/null +++ b/link.xml @@ -0,0 +1,3 @@ + + + diff --git a/link.xml.meta b/link.xml.meta new file mode 100644 index 0000000..47bead6 --- /dev/null +++ b/link.xml.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 969f6a1aebc1d3f4787bb42f9a198207 +timeCreated: 1737098208 \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..9dab81b --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "com.alicizax.unity.animationflow", + "displayName": "Aliciza X AnimationFlow", + "category": "Aliciza X", + "description": "Aliciza X AnimationFlow", + "version": "1.0.1", + "unity": "2025.1", + "keywords": [ + "Game Framework X" + ], + "repository": { + "name": "com.alicizax.unity", + "url": "http://101.34.252.46:3000/AlicizaX/", + "type": "git" + }, + "author": { + "name": "Yuliuren", + "email": "yuliuren00@gmail.com" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..0a4a01e --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0ecf5d1584776f84983d739cd5813430 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: