因为尝试过很多节点型编辑器,比如Behavior Designer、ASE,或者官方的Shader Graph,那么我就想能不能自己也做一个节点型编辑器,因为个人能力有限,所以我想找找有没有现有的节点编辑器框架可供学习,我上Github招了一下,发现其实有不少框架,而这其中xNode是最吸引我的,那么就来学习一下xNode来定制自己的节点编辑器吧


1 创建界面和节点

在节点编辑器中最重要的就是界面(Graph)和节点(Node),那么首先来让我们看一下Graph

1.1 创建Graph

通过Assets——Create——NodeGraph C# Script我们就能快速创建Graph的代码,代码也十分简洁
这里要注意:

  1. 如果需要当前Graph中的数据可以被序列化,我们需要添加[System.Serializable]特性,也可以通过修改"xNode_NodeGraphTemplate.cs.txt"来统一修改
  2. 通过修改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也能看出来

android tp 节点 安卓节点工具_Unity

这里我使用了Odin插件,所以看上去是这样的

1.3 创建Node

和创建Graph类似,通过Assets——Create——NodeGraph C# Script我们就能快速创建Node
这里要注意:

  1. 如果需要当前Node中的数据可以被序列化,我们需要添加[System.Serializable]特性
  2. 输入和输出使用[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