石家庄网站设计制作,八方建设集团有限公司网站,贵阳微网站建设公司哪家好,asp.net 网站开发视频1、创建节点区域脚本
其中的new class UxmlFactory#xff0c;可以让该元素显示在UI Builder中#xff0c;我们就可以在Library-Project中看到我们新建的这两个UI元素#xff0c;就可以拖入我们的UI窗口编辑了
public class NodeTreeViewer : GraphView
{public new class…1、创建节点区域脚本
其中的new class UxmlFactory可以让该元素显示在UI Builder中我们就可以在Library-Project中看到我们新建的这两个UI元素就可以拖入我们的UI窗口编辑了
public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactoryNodeTreeViewer, UxmlTraits { }
} 默认的GraphView是一片黑屏。在这里我们给我们的GraphView窗口添加上网格和拖拽缩放功能。
public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactoryNodeTreeViewer, UxmlTraits { }public NodeTree tree;public ActionNodeView OnNodeSelected;public NodeTreeViewer(){Insert(0, new GridBackground());this.AddManipulator(new ContentZoomer());this.AddManipulator(new ContentDragger());this.AddManipulator(new SelectionDragger());this.AddManipulator(new RectangleSelector());var styleSheet AssetDatabase.LoadAssetAtPathStyleSheet(Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss);styleSheets.Add(styleSheet);}
} uss代码参考上面代码的uss路径要根据项目实际路径进行设置。
GridBackground{--grid-background-color: rgb(40,40,40);--line-color: rgba(193,196,192,0.1);--thick-line-color: rgba(193,196,192,0.1);--spacing: 15;
}2、创建节点和删除选中元素
2.1 创建节点类
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;public class NodeView : UnityEditor.Experimental.GraphView.Node
{public Node node;public Port input;public Port output;public ActionNodeView OnNodeSelected;public NodeView(Node node){this.node node;this.title node.name;this.viewDataKey node.guid;style.left node.position.x;style.top node.position.y;CreateInputPorts();CreateOutputPorts();}//创建输入端口private void CreateInputPorts(){input InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));if(input ! null ){input.portName ;inputContainer.Add(input);}}//创建输出端口private void CreateOutputPorts(){output InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));if (output ! null){output.portName ;outputContainer.Add(output);}}//选中该节点时传递事件public override void OnSelected(){base.OnSelected();if( OnNodeSelected ! null ){OnNodeSelected?.Invoke(this);}}//设置生成时位置public override void SetPosition(Rect newPos){base.SetPosition(newPos);node.position.x newPos.xMin;node.position.y newPos.yMin;}}2.2 节点区域创建节点和删除选中元素功能
//重写该方法可以添加右键菜单按钮public override void BuildContextualMenu(ContextualMenuPopulateEvent evt){var types TypeCache.GetTypesDerivedFromNode();foreach (var type in types){evt.menu.AppendAction($创建节点/{type.Name}, a CreateNode(type));}evt.menu.AppendAction(删除选中元素, DeleteSelecteNode);}//删除选中元素节点或者连线private void DeleteSelecteNode(DropdownMenuAction action){DeleteSelection();}//创建节点private void CreateNode(Type type){Node node tree.CreateNode(type);CreateNodeView(node);}private void CreateNodeView(Node node){NodeView nodeView new NodeView(node);nodeView.OnNodeSelected OnNodeSelected;AddElement(nodeView);}3、设置节点元素输出端可连接端口
public override ListPort GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){return ports.ToList().Where(endpost endpost.direction ! startPort.direction endpost.node ! startPort.node).ToList();}4、打开或者重新展示已有内容
internal void PopulateView(NodeTree tree){this.tree tree;graphViewChanged - OnGraphViewChange;DeleteElements(graphElements.ToList());graphViewChanged OnGraphViewChange;tree.nodes.ForEach(n CreateNodeView(n));tree.nodes.ForEach(n {var children tree.GetChildren(n);children.ForEach(c {NodeView parentView FindNodeView(n);NodeView childView FindNodeView(c);Edge edge parentView.output.ConnectTo(childView.input);AddElement(edge);});});}5、当节点区域元素改变时实现对应逻辑数据的修改
该方法在打开或展现时注册事件
private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange){if(graphViewChange.elementsToRemove ! null){graphViewChange.elementsToRemove.ForEach(elem { NodeView nodeview elem as NodeView;if(nodeview ! null){tree.DeleteNode(nodeview.node);}Edge edge elem as Edge;if(edge ! null){NodeView parentView edge.output.node as NodeView;NodeView childView edge.input.node as NodeView;tree.RemoveChild(parentView.node, childView.node);}});}if(graphViewChange.edgesToCreate ! null){graphViewChange.edgesToCreate.ForEach(edge {NodeView parentView edge.output.node as NodeView;NodeView childView edge.input.node as NodeView;tree.AddChild(parentView.node, childView.node);});}return graphViewChange;}6、完整代码
运行时代码Runtime Code
6.1 Node
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class Node : ScriptableObject
{public enum State { Running, Waiting}public State state State.Waiting;public bool started false;public ListNode children new ListNode();[HideInInspector] public string guid;[HideInInspector] public Vector2 position;public Node OnUpdate(){if(!started){OnStart();started true;}Node currentNode LogicUpdate();if(state ! State.Running){OnStop();started false;}return currentNode;}public abstract Node LogicUpdate();public abstract void OnStart();public abstract void OnStop();}6.2 NormalNode
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu]
public class NormalNode : Node
{[TextArea]public string dialogueContent;public override Node LogicUpdate(){// 判断进入下一节点条件成功时 需将节点状态改为非运行中 且 返回对应子节点if (Input.GetKeyDown(KeyCode.Space)){state State.Waiting;if (children.Count 0){children[0].state State.Running;return children[0];}}return this;}public override void OnStart(){Debug.Log(dialogueContent);}public override void OnStop(){Debug.Log(OnStop);}
}6.3 NodeTree
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;[CreateAssetMenu]
public class NodeTree : ScriptableObject
{public Node rootNode;public Node runningNode;public Node.State treeState Node.State.Waiting;public ListNode nodes new ListNode();public virtual void Update(){if(treeState Node.State.Running runningNode.state Node.State.Running){runningNode runningNode.OnUpdate();}}/// summary/// 对话树开始的触发方法/// /summarypublic virtual void OnTreeStart(){treeState Node.State.Running;runningNode.state Node.State.Running;}/// summary/// 对话树结束的触发方法/// /summarypublic void OnTreeEnd(){treeState Node.State.Waiting;}#if UNITY_EDITORpublic Node CreateNode(System.Type type){Node node ScriptableObject.CreateInstance(type) as Node;node.name type.Name;node.guid GUID.Generate().ToString();nodes.Add(node);if (!Application.isPlaying){AssetDatabase.AddObjectToAsset(node, this);}AssetDatabase.SaveAssets();return node;}public Node DeleteNode(Node node){nodes.Remove(node);AssetDatabase.RemoveObjectFromAsset(node);AssetDatabase.SaveAssets();return node;}public void RemoveChild(Node parent, Node child){parent.children.Remove(child);}public void AddChild(Node parent, Node child){parent.children.Add(child);}public ListNode GetChildren(Node parent){return parent.children;}
#endif
}6.4 NodeTreeRunner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NodeTreeRunner : MonoBehaviour
{public NodeTree tree;void Start(){}void Update(){if(Input.GetKeyDown(KeyCode.P)){tree.OnTreeStart();}if(tree ! null tree.treeState Node.State.Running){tree.Update();}if(Input.GetKeyDown(KeyCode.D)){tree.OnTreeEnd();}}
}可视化编辑器代码 Editor
6.5 Uxml和Uss
NodeEditor Uxml
ui:UXML xmlns:uiUnityEngine.UIElements xmlns:uieUnityEditor.UIElements xsihttp://www.w3.org/2001/XMLSchema-instance engineUnityEngine.UIElements editorUnityEditor.UIElements noNamespaceSchemaLocation../../../../UIElementsSchema/UIElements.xsd editor-extension-modeTrueStyle srcNodeEditor.uss /ui:VisualElement styleflex-grow: 1; flex-direction: row;ui:VisualElement nameLeftDiv styleflex-grow: 0.3;ui:Label textInspector display-tooltip-when-elidedtrue nameInspector stylefont-size: 15px; -unity-font-style: bold; /uie:ObjectField labelNodeTree nameNodeTree styleflex-grow: 0; flex-shrink: 0; min-width: auto; align-items: stretch; flex-wrap: nowrap; flex-direction: row; width: auto; max-width: none; /InspectorViewer styleflex-grow: 1; //ui:VisualElementui:VisualElement nameRightDiv styleflex-grow: 0.7;ui:Label textNodeTreeVirwer display-tooltip-when-elidedtrue nameNodeTreeVirwer style-unity-font-style: bold; font-size: 15px; /NodeTreeViewer focusabletrue styleflex-grow: 1; //ui:VisualElement/ui:VisualElement
/ui:UXMLNodeTreeViewer Uss
GridBackground{--grid-background-color: rgb(40,40,40);--line-color: rgba(193,196,192,0.1);--thick-line-color: rgba(193,196,192,0.1);--spacing: 15;
}编辑器面板代码
6.6 NodeEdtor
using System;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;public class NodeEditor : EditorWindow
{public NodeTreeViewer nodeTreeViewer;public InspectorViewer inspectorViewer;public ObjectField nodeTreeObj;[MenuItem(MyWindows/NodeEditor)]public static void ShowExample(){NodeEditor wnd GetWindowNodeEditor();wnd.titleContent new GUIContent(NodeEditor);}public void CreateGUI(){// Each editor window contains a root VisualElement objectVisualElement root rootVisualElement;// Import UXMLvar visualTree AssetDatabase.LoadAssetAtPathVisualTreeAsset(Assets/NodeEditor/Editor/UI/NodeEditor.uxml);visualTree.CloneTree(root);var styleSheet AssetDatabase.LoadAssetAtPathStyleSheet(Assets/NodeEditor/Editor/UI/NodeEditor.uss);root.styleSheets.Add(styleSheet);nodeTreeViewer root.QNodeTreeViewer();inspectorViewer root.QInspectorViewer();nodeTreeObj root.Q(NodeTree) as ObjectField;nodeTreeObj.objectType typeof(NodeTree);nodeTreeViewer.OnNodeSelected OnNodeSelectionChanged;}private void OnNodeSelectionChanged(NodeView view){inspectorViewer.UpdateSelection(view.node);}private void OnSelectionChange(){NodeTree tree Selection.activeObject as NodeTree;if (tree){nodeTreeViewer.PopulateView(tree);nodeTreeObj.value tree;}else{nodeTreeViewer.CloseNodeTreeViewer();nodeTreeObj.value null;}}}
6.7 NodeTreeViewer
using BehaviorDesigner.Runtime.Tasks.Unity.UnityInput;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;public class NodeTreeViewer : GraphView
{public new class UxmlFactory : UxmlFactoryNodeTreeViewer, UxmlTraits { }public NodeTree tree;public ActionNodeView OnNodeSelected;private Vector2 curMousePos;ContentZoomer contentZoomer;ContentDragger contentDragger;public NodeTreeViewer(){Insert(0, new GridBackground());contentZoomer new ContentZoomer();this.AddManipulator(contentZoomer);contentDragger new ContentDragger();this.AddManipulator(contentDragger);this.AddManipulator(new SelectionDragger());this.AddManipulator(new RectangleSelector());var styleSheet AssetDatabase.LoadAssetAtPathStyleSheet(Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss);styleSheets.Add(styleSheet);this.RegisterCallbackMouseDownEvent(OnMouseDown);}private void OnMouseDown(MouseDownEvent evt){Debug.Log(evt.localMousePosition);curMousePos evt.localMousePosition;Debug.Log(contentZoomer.scaleStep);Debug.Log(contentZoomer.referenceScale);//Debug.Log(contentDragger.p)}public override void BuildContextualMenu(ContextualMenuPopulateEvent evt){var types TypeCache.GetTypesDerivedFromNode();foreach (var type in types){evt.menu.AppendAction($创建节点/{type.Name}, a CreateNode(type));}evt.menu.AppendAction(删除选中元素, DeleteSelecteNode);}private void DeleteSelecteNode(DropdownMenuAction action){DeleteSelection();}private void CreateNode(Type type){Node node tree.CreateNode(type);node.position curMousePos;CreateNodeView(node);}private void CreateNodeView(Node node){NodeView nodeView new NodeView(node);nodeView.OnNodeSelected OnNodeSelected;AddElement(nodeView);}internal void PopulateView(NodeTree tree){this.tree tree;graphViewChanged - OnGraphViewChange;DeleteElements(graphElements.ToList());graphViewChanged OnGraphViewChange;tree.nodes.ForEach(n CreateNodeView(n));tree.nodes.ForEach(n {var children tree.GetChildren(n);children.ForEach(c {NodeView parentView FindNodeView(n);NodeView childView FindNodeView(c);Edge edge parentView.output.ConnectTo(childView.input);AddElement(edge);});});}public void CloseNodeTreeViewer(){this.tree null;graphViewChanged - OnGraphViewChange;DeleteElements(graphElements.ToList());}private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange){if(graphViewChange.elementsToRemove ! null){graphViewChange.elementsToRemove.ForEach(elem { NodeView nodeview elem as NodeView;if(nodeview ! null){tree.DeleteNode(nodeview.node);}Edge edge elem as Edge;if(edge ! null){NodeView parentView edge.output.node as NodeView;NodeView childView edge.input.node as NodeView;tree.RemoveChild(parentView.node, childView.node);}});}if(graphViewChange.edgesToCreate ! null){graphViewChange.edgesToCreate.ForEach(edge {NodeView parentView edge.output.node as NodeView;NodeView childView edge.input.node as NodeView;tree.AddChild(parentView.node, childView.node);});}return graphViewChange;}NodeView FindNodeView(Node node){return GetNodeByGuid(node.guid) as NodeView;}public override ListPort GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){return ports.ToList().Where(endpost endpost.direction ! startPort.direction endpost.node ! startPort.node).ToList();}}6.8 NodeView
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;public class NodeView : UnityEditor.Experimental.GraphView.Node
{public Node node;public Port input;public Port output;public ActionNodeView OnNodeSelected;public NodeView(Node node){this.node node;this.title node.name;this.viewDataKey node.guid;style.left node.position.x;style.top node.position.y;CreateInputPorts();CreateOutputPorts();}private void CreateInputPorts(){input InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));if(input ! null ){input.portName input;inputContainer.Add(input);}}private void CreateOutputPorts(){output InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));if (output ! null){output.portName output;outputContainer.Add(output);}}public override void OnSelected(){base.OnSelected();if( OnNodeSelected ! null ){OnNodeSelected?.Invoke(this);}}public override void SetPosition(Rect newPos){Debug.Log(newPos);base.SetPosition(newPos);node.position.x newPos.xMin;node.position.y newPos.yMin;}}6.9 InspectorViewer
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;public class InspectorViewer : VisualElement
{public new class UxmlFactory : UxmlFactoryInspectorViewer, UxmlTraits { }Editor editor;public InspectorViewer(){//this.AddManipulator(new drag)}internal void UpdateSelection(Node node){Clear();UnityEngine.Object.DestroyImmediate(editor);editor Editor.CreateEditor(node);IMGUIContainer container new IMGUIContainer(() {if (editor.target){editor.OnInspectorGUI();}});Add(container);}}【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具_unity uibuilder-CSDN博客
[Unity] GraphView 可视化节点的事件行为树(二) UI Toolkit介绍制作事件行为树的UI_unity graphview-CSDN博客