因为尝试过很多节点型编辑器,比如Behavior Designer、ASE,或者官方的Shader Graph,那么我就想能不能自己也做一个节点型编辑器,因为个人能力有限,所以我想找找有没有现有的节点编辑器框架可供学习,我上Github招了一下,发现其实有不少框架,而这其中xNode是最吸引我的,那么就来学习一下xNode来定制自己的节点编辑器吧
1 创建界面和节点
在节点编辑器中最重要的就是界面(Graph)和节点(Node),那么首先来让我们看一下Graph
1.1 创建Graph
通过Assets——Create——NodeGraph C# Script我们就能快速创建Graph的代码,代码也十分简洁
这里要注意:
- 如果需要当前Graph中的数据可以被序列化,我们需要添加[System.Serializable]特性,也可以通过修改"xNode_NodeGraphTemplate.cs.txt"来统一修改
- 通过修改CreateAssetMenu特性中的参数可以改变创建Asset的窗口选项和名称
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XNode;
[CreateAssetMenu]
//CreateAssetMenu(fileName = "String Graph", menuName = "xNode Examples/String Graph")
public class NewNodeGraph : NodeGraph { }
1.2 NodeGraph解析
接下来就对代码作简单的解析
///这是所有NodeGraph的基类
[Serializable]
public abstract class NodeGraph : ScriptableObject
{
///目前Graph中所有的Node
[SerializeField] public List<Node> nodes = new List<Node>();
///通过模板为当前Graph添加Node,本质上还是使用了下面的Type来添加
public T AddNode<T>() where T : Node {
return AddNode(typeof(T)) as T;
}
///通过Type为当前Graph添加节点
public virtual Node AddNode(Type type) {
Node.graphHotfix = this;
Node node = ScriptableObject.CreateInstance(type) as Node;
node.graph = this;
nodes.Add(node);
return node;
}
///复制一个Node
public virtual Node CopyNode(Node original) {
Node.graphHotfix = this;
Node node = ScriptableObject.Instantiate(original);
node.graph = this;
node.ClearConnections();
nodes.Add(node);
return node;
}
///安全的移除一个Node以及它的所有Connect(在之后的Node篇会解析的,大概)
public virtual void RemoveNode(Node node) {
node.ClearConnections();
nodes.Remove(node);
if (Application.isPlaying) Destroy(node);
}
///清除当前Graph中的所有Node和Connect
public virtual void Clear() {
if (Application.isPlaying) {
for (int i = 0; i < nodes.Count; i++) {
Destroy(nodes[i]);
}
}
nodes.Clear();
}
///深拷贝一个新的Graph
public virtual XNode.NodeGraph Copy() {
//实例化一个新的Graph
NodeGraph graph = Instantiate(this);
//实例化新Graph中的所有Node
for (int i = 0; i < nodes.Count; i++) {
if (nodes[i] == null) continue;
Node.graphHotfix = graph;
Node node = Instantiate(nodes[i]) as Node;
node.graph = graph;
graph.nodes[i] = node;
}
//重新连接Node中联系
for (int i = 0; i < graph.nodes.Count; i++) {
if (graph.nodes[i] == null) continue;
foreach (NodePort port in graph.nodes[i].Ports) {
port.Redirect(nodes, graph.nodes);
}
}
return graph;
}
//大家懂的
protected virtual void OnDestroy() {
//顺便清空其中所有的节点和连接
Clear();
}
}
其实这个类非常的简单,它就是维护了一个Node的链表,进行的操作也是对这个链表进行操作(增加、删除、拷贝、清空这些基本操作),我们在它的案例中查看Asset也能看出来
这里我使用了Odin插件,所以看上去是这样的
1.3 创建Node
和创建Graph类似,通过Assets——Create——NodeGraph C# Script我们就能快速创建Node
这里要注意:
- 如果需要当前Node中的数据可以被序列化,我们需要添加[System.Serializable]特性
- 输入和输出使用[Input]和[Output]特性即可
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XNode;
public class NewNode : Node
{
//[Input] public float a;
//[Input] public float b;
//[Output] public float result;
//初始化
protected override void Init() {
base.Init();
}
//得到返回值
public override object GetValue(NodePort port) {
return null; // Replace this
}
}
在这之前我们先要介绍NodePort,就类似在Graph中维护了一个Node的链表,在Node中也维护着一个NodePort的链表,而这个就是Node的接口(Port),所以我们先来介绍NodePort,当然这个NodePort也是相当复杂的,这里就直接简单解析一下代码
因此在介绍Node之前,我们在下一章先要介绍NodePort