Unity可视化脚本之——xNode【2】官方wiki文档试读

写在前面

xNode的wiki文档是英文,我边读边摘录重要信息并用中文做了笔记,希望能帮助到大家,其中必有错漏的地方,也请大家留言指出,谢谢!

目前的初稿是我刚写好的,后面我会继续修改,在研究xNode和用xNode制作插件的过程中,我会随时核对这些文档,并修订。

要研究xNode的朋友,还是建议去看原文。
2021-10-24

一、前言

Thor Brigsted edited this page 18 days ago · 30 revisions

欢迎来到xNode wiki!
如果阁下初来乍到,大可跳到wiki中getting started部分,并从这里开始研究和学习。

因为某些原因,我不想在wiki里面展示api文档并长期维护,反而我推荐诸位去阅读源码,或者你可以在编辑器里面,用点号[.]来查看各个类的成员和方法。

二、API

Thor Brigsted edited this page on 7 Mar 2019 · 3 revisions

因为一旦写了API文档,那么这个文档势必要随时更新,这也是一件浩大的工程,可惜我不是三头六臂,其实我是觉得写文档没写代码那么愉快,所以,劳烦各位客官动动身子,到源码文件里去看一下,或者在编辑器里面浏览一下各个class成员、方法以及对应的注释,我们的项目的源码,注释都是十分完备的,大家放心服用哈。

  • 示例:如何在编辑器中愉快的使用源码注释
    在这里插入图片描述

三、数据流 Data Flow

Thor Brigsted edited this page on 1 Apr 2018 · 2 revisions

要使节点性能最大化,取决于你如何选择最合适的数据流方式。在你的项目里面,可能有很多种数据流的方式可以预选,那么你就选择最适合的一种。请注意,xNode只提供各种流可能用到的方法,而不是帮你实现各种流,我们坚信——授人以鱼不如授人以渔。

  • Forward
    向前的数据流是什么意思呢,因为节点有input和output端口,如果节点的input值发生变化(就是有输入)的时候,节点就进行计算,并把计算结果缓存起来,然后我们激发output上连接的后续节点,并把当前节点的output值传递给下一个节点的input,如此循环往复,子又生孙,孙又生子,直到地球爆炸(直到节点结束)。

  • Backward
    向后的数据流又是什么意思呢,所谓的后,就是从最后一个节点开始往前回溯调用,直到第一个节点。当你请求最后一个节点的output值的时候,激发了本节点上的一个计算,计算什么东东,先是请求本节点input的值,然后用input的值来计算output的值。同理,在计算本节点input值的时候,判断该input节点是否有父节点,然后层层往前调用,直到第一个节点。

  • 【疑问】
    当在最后一个节点上request一个值的时候,是不是自动遍历全网,逐个往前请求?需要查源码和注释,然后自己弄一个测试验证的案例。

  • None
    无数据流,譬如构建状态机或者类似的项目时,数据流不是重点,重点是啥呢,你在节点图上,通过节点的连接关系,往前走或者往后走,直到走遍全球,走遍每一个节点。

四、动态端口列表 Dynamic Port List

Thor Brigsted edited this page on 6 Oct 2019 · 8 revisions

提示各位客官: Dynamic port lists 是实验性的. 请大家不吝赐教,把你的bugs提交给我们

  • 动态端口列表是啥?

它不是一个class或者type,那它到底是什么,它是一个只能在编辑器中使用的便利工具,有了它,你就可以管理一堆动态端口,甚至,你可以用array或者list来维护和管理这些动态端口。

  • 动态端口怎么玩呢?
    创建动态窗口有两种方式,一是在input/output属性中设置参数[Output(dynamicPortList = true)],另一种是在node编辑器中,调用方法 NodeEditorGUILayout.DynamicPortList

当把list或者array作为backing field type的时候,列表中的每个端口会被毁赋予一个可以编辑的值。Non-array字段可以工作,但是每个端口不会显示backing value值。

  • 如何获取一个端口呢?
    首先,被动态创建的端口,他们有一个统一的命名规范 [端口名][空格][序号] 譬如:"myArray 0"可以代表你的第一个端口。访问一个端口的method就是:GetPort(“myArray 0”)。

  • 小窍门
    Customize dynamic port list
    You may want to customize the way the list is drawn, either for visual or functional purpose. You can do this by modifying the list delegates after the list is created, by manually drawing the list in a custom NodeEditor with the method NodeEditorGUILayout.DynamicPortList which takes an Action onCreation parameter.
    A good starting point is to copy the delegate you want to override from the method NodeEditorGUILayout.CreateReorderableList, paste it in your onCreate override, and make your modifications.

More info on ReorderableLists here

public class MyNodeEditor : NodeEditor {
    public override void OnBodyGUI() {
        // Draw GUI
        NodeEditorGUILayout.DynamicPortList(
            "myFloatList", // field name
            typeof(float), // field type
            serializedObject, // serializable object
            NodePort.IO.Input, // new port i/o
            Node.ConnectionType.Override, // new port connection type
            OnCreateReorderableList); // onCreate override. This is where the magic happens.
    }

    void OnCreateReorderableList(ReorderableList list) {
        // Override drawHeaderCallback to display node's name instead
        list.drawHeaderCallback = (Rect rect) => {
            string title = serializedObject.targetObject;
            EditorGUI.Label(rect, title);
        };
    }
}

五、动态端口

Thor Brigsted edited this page on 22 Apr 2020 · 4 revisions

class NodePort
  • 动态端口是啥?
    port是啥,请看这里,顾名思义,动态port肯定是port中的一种喽。
    动态端口被用在static port上,只是这些端口可以被添加或者删除,无论是编辑模式或者运行时模式都可以如此操作。

由于动态端口没有绑定到一个可系列化的字段,因此node editor里面进行绑定操作。

  • 为什么要用动态端口?

使用动态端口可能有多种原因。你可能为了显示一个端口,这个端口的类型是Unity没有系列化的类型。动态端口可以是任何类型。你可能想要动态地添加或者删除一些端口。InstancePortList 可以帮你达成心愿。动态端口不需要可系列化的字段。

  • 动态端口要怎么玩呢?
    你可以在一个节点实例上自由地添加一个或者多个动态端口。更常见的作法是——你可能想通过NodeEditor脚本来实现,如此操作的API如下所示:
void AddDynamicPorts(Node node) {  
 node.AddDynamicInput(typeof(string), fieldName: "myDynamicInput");   
 node.AddDynamicOutput(typeof(int), fieldName: "myDynamicOutput");
}

void RemoveDynamicPorts(Node node) {  
 node.RemoveDynamicPort("myDynamicInput");   
 node.RemovDynamicPort("myDynamicOutput");
}

就像普通端口一样,动态端口也可以被绘制,如何实现呢,在node editor中调用下面的方法:

NodeEditorGUILayout.DrawPort(myDynamicPort);
  • 从技术上来讲…
    They are stored in the same array as static ports. The only thing that sets the two apart is a bool.
    动态端口与静态端口都存储在同一个数组中,…【不解】…

当Unity重新编译时,xNode对所有节点类型进行检查,并用[Input]和[Output]属性同步序列化端口,删除脚本中不再存在的序列化端口,并序列化可能已经添加的新端口。动态端口忽略此步骤。

六、FAQ

Thor Brigsted edited this page on 4 Apr 2020 · 7 revisions

  • 你听说过新的UIElements吗?

题外话——UIElement背景说明【来自网络】:UIElement(现更名为UI ToolKit但是程序集名称还是UIElement,雀食没话说)是Unity新推出的一种UI解决方案,目标是一站式解决Editor+Runtime的UI设计需求,使用C# + HTML的形式进行开发,其中HTML用以定义UI样式和内容,C#引用HTML定义内容+绑定数据,并且与GamePlay进行交互。

xNode所做的一个关键事项就是向后兼容,一直兼容到5.3【疑问:5.3指的是Unity5.3吗?】。这就意味着UIElements目前不是我们的一个工作选项,因为我也没有时间来重写整个框架,以便xNode能够使用这套新的UI系统。然而 ,不要让这件事阻挡你去创建一个基于UIElements的fork,如果你创建了基于UIElement的分叉,我会把它加入到项目链接中。

  • 我如何在xNode中引用场景里的objects?
    关于这个话题,解决之道就是在scene里面创建graph,而不是创建一个asset的graph。你可以把SceneGraph组件挂载到任何GameObject上。在scene里面创建的Graph可以引用场景里面的object。遗憾的是,目前还不支持prefabs,也就是预制体上不能挂在sceneGraph。

曲线救国的方法就是,你可以创建自己的ID查找系统(ID lookup system)。

  • 要不要做另一个功能——节点分组(Node grouping)?
    节点分组的工作已经尝试过好几次了,然而都没有达到令人满意的程度,所以,目前然仍在todo的清单上。

七、Getting Started

Thor Brigsted edited this page on 5 Sep 2019 · 18 revisions

着手开始弄一个属于你自己的节点系统其实是很快很简单的事情。正如前面的章节所说,一个graph 类是从NodeGraph父类继承而来,一个自定义的节点类继承自Node基类。一个graph包含了多个节点,一个节点可以访问它自己的端口,还可以访问连接到它们端口上的其它节点。有了这些节点以及节点之间的连接关系,你想要实现什么功能,这些业务代码需要你自己去实现。

图和节点都继承自ScriptableObject,这些图和节点最终以assets的形式保存在你的项目文件夹里。

如果你正在寻找案例教程,我推荐你看一下这两个链接: examples branchlist of opensource xNode plugins.

  • 需要明白的核心概念
    学习xNode,你最好搞清楚以下几个概念:
    Graphs——图
    Nodes——节点
    Ports——端口

  • 创建一个节点图(NodeGraph)
    巧妇难为无米之炊,你要创建节点,你的先创建一个节点图!节点图就是一个简单的类,它的作用就是操作和计算它所包含的节点。

一个简单的NodeGraph脚本可以这样写:

// SimpleGraph.cs

[CreateAssetMenu]
public class SimpleGraph : NodeGraph { }

小提示: 通过以下菜单,你可以麻利地创建一个节点图的脚本,什么菜单呢,就是:【Assets】 > 【Create】 > 【xNode】 > 【NodeGraph C# Script】

上面代码示例中的

[CreateAssetMenu]

是啥意思呢?它的作用就是在项目窗口里面提供一个右键菜单——【Right-Click】>【Create】>【SimpleGraph】,通过这个菜单,你可以创建一个asset资源文件。详情请看More info

要使节点图能够正常工作,是不是需要其它前期准备,完全不需要,你只要在asset里面双击节点图,便可以顺利打开这个节点图。有许多可以重载的function,它们可以帮你控制节点图的外观,以便提供不同的用户体验。

FAQ: 为什么我不能从窗口菜单里面访问xNode呢?
xNode是一个框架,用xNode进行插件编写的开发人员,他大概也不关心他的xNode存在于【Window】>【xNode】菜单之下,而且,如果不修改xNode的核心代码,他是不能够移除xNode的。如果你想添加它的快捷方式,你可以通过编辑器脚本来实现,请参考MenuItem

  • 如何创建一个节点(Node)?
    节点类似常规的ScriptableObjects,不同之处在于你可以通过节点所属的NodeGraph来编辑节点,更进一步,你可以创建和访问节点的inputs和outputs端口。创建一个节点,只需要从Node基类进行继承,请看下面的代码:
// SimpleNode.cs

public class SimpleNode : Node { 
  [Input] public float a;
  [Output] public float b;

  public override object GetValue(NodePort port) {
    if (port.fieldName == "b") return GetInputValue<float>("a", a);
    else return null;
  }
}

小提示: 你可以通过以下菜单快速创建一个node脚本,【Assets 】>【Create 】>【Node C# Script】

正如上代码所示,你可能会对[Input]和[Output]比较好奇,这两属性标签的作用就是让你定义一些静态的端口,这些端口则可以连接到别的节点的端口,这样节点与节点之间就有了connection的关系。那么,这个属性标签后面的字段名还有别的奇妙用法不,当然有,任何时候你都可以通过字段名字来访问字段对应的节点端口,访问的方式为NodePort GetInputPort(string fieldName) 或者 T GetInputValue(string fieldName, T fallback)。只有可系列化的字段才会显示出来。

凡是有output端口的节点,重写GetValue(NodePort port)方法是非常重要的,因为当你用带GetInputValue的时候,往往会调用GetValue方法。要请求的节点端口会被作为参数传入,计算结果会被返回给请求的节点。在本例中,我们判断被请求的节点是不是“b”,如果是,我们将把“a”端口的值返回。由于只有一个output端口,因此这样的判断并不是必须的,因为如果该节点的后续节点要请求数据的话,也只会请求到节点的端口"b"。

小提示:

  • F键——进入home view
    home view 的意思就是自动聚焦到你的节点。

  • 双击节点的header可以居中它
    Does exactly what it says on the tin. It would look silly to have just one tip without a drop-down description, wouldn’t it?

  • Right-click while dragging a connection to place a reroute point
    Reroute points allow node connection noodles to follow a certain path before reaching their destination.

八、图编辑器——Graph Editors

Thor Brigsted edited this page on 3 May 2020 · 17 revisions

class NodeGraph : NodeEditorBase
  • Graph Editors是啥东东?
    每一个图(graph)都是通过图编辑器(GraphEditor)来绘制的,可参照对比 Unity’s custom editors,当然了,你也可以重载那些用来绘图的函数。

  • Graph Editors怎么玩?
    创建自定义节点图编辑器与为其它class创建自定义inspectors极为相似。
    节点图编辑器的基类是NodeGraphEditor,且要有一个属性标签**[CustomNodeGraphEditor(System.Type type)]**,需要注意的是,你自定义的节点编辑器class不能是abstract类型(不能是抽象类)。

编辑器脚本需要放在一个editor folder里面,在build的时候,它们不会参与build。

一个最简单的图编辑器脚本如下:

[CustomNodeGraphEditor(typeof(MyGraph))]
public class MyGraphEditor : NodeGraphEditor {

}
  • 小提示
    1、 筛选节点,让某些节点在创建菜单中显示
    GetNodeMenuName override lets you specify the path of a specified node type, but it also lets you hide it by returning null. To filter all but nodes deriving from a specific base class you can use this snippet.
public override string GetNodeMenuName(Type type) {
    if (typeof(MyBaseNode).IsAssignableFrom(type)) {
        return base.GetNodeMenuName(type);
    } else return null;
}

2、Store preferences specific to your node graph or project
Add a unique EditorPrefs key to the attribute

[CustomNodeGraphEditor(typeof(MyGraph), "MyGraph.Settings")]
Override GetDefaultPreferences(); to set default preferences
public override NodeEditorPreferences.Settings GetDefaultPreferences() {
    return new NodeEditorPreferences.Settings() {
        gridBgColor = Color.black,
        gridLineColor = Color.white,
        typeColors = new Dictionary<string, Color>() {
            { typeof(string).PrettyName(), Color.yellow },
            { typeof(MyType).PrettyName(), new Color(1,0.5f,0.6f) }
        }
    };
}

3、Repaint each frame
Sometimes you may want your nodes to repaint every frame. This is achievable though spamming ‘repaint me’ in OnGUI. Don’t worry, it won’t freeze 😃

public override void OnGUI() {
    // Keep repainting the GUI of the active NodeEditorWindow
    NodeEditorWindow.current.Repaint();
}

九、图——Graphs

Thor Brigsted edited this page on 6 Apr 2020 · 12 revisions

class NodeGraph : ScriptableObject
  • 什么是图?
    每一个xNode的项目都是从创建一个图开始的。图包含了一堆节点,你的这些节点能做啥这可使由你说了算,意思就是你自己来实现功能代码。

你可以通过图编辑器来自定义图的外形。

  • 为什么是图?
    一个graph是这个graph所包含的所有node的顶层入口。根据你自己的需求,你可以在你的graph中实现以下method——GetFirstNode, GetRootNode, GetResult, UpdateAI 等等。当然了,你也可以在你的graph中定义许多变量,这些变量被所有的node使用,譬如说你可以为你的状态机graph定义一个currentNode字段。

  • 怎么玩转图?
    所有graph的代码其实都很简单,它们全部继承自NodeGraph基类。最理想的做法是,给你的graph代码增加一个属性**[[CreateAssetMenu]]**,这样你就可以在Unity中通过Create菜单创建一个graph asset了。

[CreateAssetMenu]
public class SimpleGraph : NodeGraph { }

注意啊graph assets不能引用场景里的的objects。如果你要引用场景里的objects,请用scene graphs

在下面的例子中,你可以为你的打造一个自定义的入口。比如说,你定义一个StartGraph()方法,通过这个方法,你遍历所有节点,并调用符合条件的所有节点的Trigger()方法。

[CreateAssetMenu]
public class SimpleGraph : NodeGraph {

  public RootNode GetRootNode() {
    for (int i = 0; i < nodes.Count; i++) {
      if (nodes[i] is NewNode) return nodes[i] as NewNode;
    }
    return null;
  }
}

小提示
graph对[ContextMenu]的支持。

图是支持[ContextMenu]属性的。非常简单,只要你把 [ContextMenu] 属性代码添加到一个非静态方法前面,当你在网格上鼠标右键的时候,创建这个图的菜单就会显示出来。要了解ContextMenu的更多资料请移步这里

十、它是怎么工作的

Thor Brigsted edited this page on 2 Jan 2018 · 1 revision

  • 这一切是如何运作的
    xNode几乎完全存在于编辑器脚本中,build的时候只有图和节点会被build进去。我将在这一章节里面来解释xNode到底在幕后做了些啥事情。

  • 编辑器(The Editor)
    编辑器是xNode中最复杂的部分,但其实上它相对简单,它的作用就是配合Unity来工作,而不是与Unity对着干。节点绘制使用标准的EditorGUILayout中的PropertyField来完成,并且还提供了免费的undo功能。许多反射数据会被提前缓存,这样就能提高运行速度。

未完待续…

  • 节点图(NodeGraphs) 和 节点(Nodes)
    节点图仅仅提供以下功能:一是作为一个容器,拿来装在节点,第二个功能就是提供多种访问节点的方法。所有的节点,它们都包含一个position属性、一个端口字典以及各种节点之间访问的方法。字典的用途就是提供快速的访问方法,给定一个端口的名字,然后你就可以快速的访问这个端口。

未完待续…

  • 节点端口(Node Ports)
    一个节点的端口其实就是一个指针,它指向其它端口。在内部实现上,系统对input和output端口并没有区别对待,所不同的只是在创建的时候给了一个枚举值。【意思就是,input和output端口,本质上没啥区别,所不同的就是名字不同,一个被叫input一个叫output,input和output也是相对的,因为从不同方向遍历节点是,input和output其实是可以互换的

未完待续…

  • 系列化
    系列化是免费的,因为Node和NodeGraph都继承自ScriptableObject,ScriptableObject就是为系列化而生的,我们算是搭了个顺风车。这意味着,无论是运行时还是编辑器状态,它们使用相同的系列化规则。

未完待续…

十一、节点(Node)

Thor Brigsted edited this page on 8 Nov 2018 · 12 revisions

Node class是所有节点的基类,你自己定义的所有节点都要继承自Node

public abstract class XNode.Node
    : ScriptableObject
  • 字段(fields)
TypeNameSummary
NodeGraphgraphParent NodeGraph
Vector2positionPosition on the NodeGraph

-属性(Properties)

TypeNameSummary
IEnumerableInputsIterate over all inputs on this node.
IEnumerableInstanceInputsIterate over all instance inputs on this node.
IEnumerableInstanceOutputsIterate over all instance outputs on this node.
IEnumerableInstancePortsIterate over all instane ports on this node.
IEnumerableOutputsIterate over all outputs on this node.
IEnumerablePortsIterate over all ports on this node.
  • 方法(methods)
TypeNameSummary
NodePortAddInstanceInput(Type type, String fieldName = null)Add a dynamic, serialized port to this node
NodePortAddInstanceOutput(Type type, String fieldName = null)Add a dynamic, serialized port to this node
voidClearConnections()Disconnect everything from this node
voidClearInstancePorts()Removes all instance ports from the node
NodePortGetInputPort(String fieldName)Returns input port which matches fieldName
TGetInputValue(String fieldName, T fallback = null)
T[]GetInputValues(String fieldName, T[] fallback)
NodePortGetOutputPort(String fieldName)Returns output port which matches fieldName
NodePortGetPort(String fieldName)Returns port which matches fieldName
ObjectGetValue(NodePort port)Returns a value based on requested port output. Should be overridden before used.
BooleanHasPort(String fieldName)
voidInit()Initialize node. Called on creation.
voidOnCreateConnection(NodePort from, NodePort to)Called after a connection between two ports is created
voidOnRemoveConnection(NodePort port)Called after a connection is removed from this port
voidRemoveInstancePort(String fieldName)Remove an instance port from the node
voidRemoveInstancePort(NodePort port)Remove an instance port from the node
voidVerifyConnections()Checks all connections for invalid references, and removes them.

十二、节点编辑器(Node Editor)

Thor Brigsted edited this page on 10 Apr 2020 · 18 revisions

class NodeEditor : NodeEditorBase
  • 什么是节点编辑器
    每个节点(Node)都是用节点编辑器(Node Editor)绘制出来的。就像Unity自定义编辑器一样,你可以重写那些绘制节点的函数,比如内联端口( inlining ports)、改变颜色、增加预览的贴图等等。

  • 节点编辑器怎么玩
    创建自定义的节点编辑器的方法,类似于为class创建一个自定义的面板观察器(custom inspectors)。节点编辑器的基类是NodeEditor,并且它有一个属性标签——[CustomNodeEditor(System.Type type)],自定义的节点编辑器class不能定义成抽象类。编辑器脚本同样需要一个编辑器文件夹(editor folder),而且,在build的时候,这些代码不会参与build。

定义一个节点class:

// SimpleNode.cs

public class SimpleNode : Node{
    public int a;
    public int b;
    [Output] public int sum;

    public override object GetValue(NodePort port) {
        return GetSum();
    }

    public float GetSum() {
        return a + b;
    }
}

为这个节点class量身打造一个节点编辑器:

// Editor/SimpleNodeEditor.cs

[CustomNodeEditor(typeof(SimpleNode))]
public class SimpleNodeEditor : NodeEditor {
    private SimpleNode simpleNode;

    public override void OnBodyGUI() {
        if (simpleNode == null) simpleNode = target as SimpleNode;

        // Update serialized object's representation
        serializedObject.Update();

        NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("a"));
        NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("b"));
        UnityEditor.EditorGUILayout.LabelField("The value is " + simpleNode.GetSum());
        NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("sum"));

        // Apply property modifications
        serializedObject.ApplyModifiedProperties();
    }
}

在这里插入图片描述
***请注意:***有些操作,比如增加一个动态端口,不能放在serializedObject.Update/Apply方法里。

  • 小技巧
    1、使用EditorStyles更改节点上文本字体的颜色
    第一步:预先缓存EditorStyles.label,这样就不会干扰到其它编辑器【疑问:影响到谁】。
private static GUIStyle editorLabelStyle;

void OnBodyGUI() {
  if (editorLabelStyle == null) editorLabelStyle = new GUIStyle(EditorStyles.label);
}

第二步:在绘制GUI的时候,临时改变EditorStyles.label的值

void OnBodyGUI() {
  if (editorLabelStyle == null) editorLabelStyle = new GUIStyle(EditorStyles.label);
  EditorStyles.label.normal.textColor = Color.white;
  base.OnBodyGUI();
  EditorStyles.label.normal = editorLabelStyle.normal;
}

2、为你的节点添加一个预览用的贴图

在这里,我们可以使用base.OnBodyGUI()来绘制默认编辑器,然后在添加其他东西。

public override void OnBodyGUI() {
  // Draw default editor
  base.OnBodyGUI();

  // Get your node
  MyNode node = target as MyNode;

  // Draw your texture
  EditorGUILayout.LabelField(new GUIContent(node.myTexture));
}

十三、节点中的Input和Output

Thor Brigsted edited this page on 21 Jan 2019 · 4 revisions

Input和Output的定义:

public [Input(ShowBackingValue backingValue, ConnectionType connectionType, bool instancePortList = false)];
public [Output(ShowBackingValue backingValue, ConnectionType connectionType, bool instancePortList = false)];
ParametersSummary
backingValueWhen to show the field inspector associated with this NodePort.
connectionTypeShould we allow multiple connections?
instancePortListDisplay a reoderable list of ports, optionally using array data as backing values

把一个public或者private的系列化字段指定input或者output端口

public class ExampleNode : Node{
    [Input] public float a;
    [Output] public float b;
}

十四、Node.AddInstanceInput

Thor Brigsted edited this page on 5 Mar 2019 · 6 revisions

为一个节点添加一个动态的、系列化的端口,input属性的端口。

public NodePort AddInstanceInput(Type type, string fieldName = null);
ParametersSummary
typeNodePort value type.
fieldNameUnique identifier used to find this NodePort. Automatically assigns a unique name if null.
using UnityEngine;
using XNode;

public class ExampleNode : Node{

    [ContextMenu("Add instance input")]
    void AddPort() {
        NodePort port = AddInstanceInput(typeof(float));
        Debug.Log("Added new input port with name " + port.fieldName);
    }
}

你也可以参考: AddInstanceOutput, AddInstancePort, RemoveInstancePort

十五、Node.AddInstanceOutput

Thor Brigsted edited this page on 23 Jan 2018 · 4 revisions

为一个节点添加一个动态的、系列化的output端口。

public NodePort AddInstanceOutput(Type type, string fieldName = null);
ParametersSummary
typeNodePort value type.
fieldNameUnique identifier used to find this NodePort. Automatically assigns a unique name if null.

实例端口不会自动显示在默认的节点观察面板(node inspectors)上。如果你要可视化的修改实例端口,那么你要为你的节点创建一个节点观察器(node inspector)。

using UnityEngine;
using XNode;

public class ExampleNode : Node{

    [ContextMenu("Add instance output")]
    void AddPort() {
        NodePort port = AddInstanceOutput(typeof(float));
        Debug.Log("Added new output port with name " + port.fieldName);
    }
}

你也可以参考: AddInstanceIntput, AddInstancePort, RemoveInstancePort

十六、Node.AddInstancePort

Thor Brigsted edited this page on 5 Mar 2019 · 4 revisions

Add a dynamic, serialized output port to this node。为节点添加动态的、系列化的输出端口。【疑问:这里的output是输出输入的意思,并不是特指Output

public NodePort AddInstancePort(Type type, NodePort.IO direction, string fieldName = null);
ParametersSummary
typeNodePort value type.
directionWhether this is an input or output port.【NodePort.IO.Input/Output】
fieldNameUnique identifier used to find this NodePort. Automatically assigns a unique name if null.
using UnityEngine;
using XNode;

public class ExampleNode : Node{

    [ContextMenu("Add instance output")]
    void AddPort() {
        NodePort port = AddInstancePort(typeof(float), NodePort.IO.Input);
        Debug.Log("Added new output port with name " + port.fieldName);
    }
}

你也可以参考: AddInstanceIntput, AddInstanceOutput, RemoveInstancePort

十七、Node.ClearConnections

Thor Brigsted edited this page on 9 Jan 2018 · 1 revision

Disconnect everything from this node。【 疑问: 是接连到这个节点上的所有的连线都断开吗?包括Input和Output上的连线。需要测试】

public void ClearConnections();

十八、Node.ClearInstancePorts

Thor Brigsted edited this page on 13 May 2018 · 3 revisions

Removes all instance ports from the node。移除这个节点上的所有实例端口(动态端口?)。

public void ClearInstancePorts();

See also: RemoveInstancePort
, AddInstancePort

十九、Node.GetInputPort

Thor Brigsted edited this page on 9 Jan 2018 · 1 revision

Returns input port which matches fieldName。给定端口的名字,获取该端口。【只有标记为Input的端口才能用么?需要测试

public NodePort GetInputPort(string fieldName);
ParametersSummary
fieldNameTarget NodePort’s unique identifier.

二十、Node.GetInputValue

Thor Brigsted edited this page on 13 May 2018 · 2 revisions

返回指定端口上输入的值,如果该端口上没有连线,则返回fallback值。【疑问: 这里的input与Input属性有对应关系吗?】

public T GetInputValue<T>(string fieldName, T fallback = default(T));
ParametersSummary
fieldNameField name of requested input port
fallbackIf no ports are connected, this value will be returned

See also: GetInputValues

二十一、Node.GetInputValues

Thor Brigsted edited this page on 13 May 2018 · 1 revision

返回指定端口上的所有输入的值。如果该端口没有连线,则返回fallback值

public T GetInputValues<T>(string fieldName, params T[] fallback);
ParametersSummary
fieldNameField name of requested input port.这里的input port是指标记为Input属性的port吗?
fallbackIf no ports are connected, this value will be returned

See also: GetInputValue

二十二、Node.GetOutputPort

Thor Brigsted edited this page on 9 Jan 2018 · 1 revision

给定一个output端口的名字,返回该端口。

public NodePort GetOutputPort(string fieldName);
ParametersSummary
fieldNameTarget NodePort’s unique identifier.

二十三、Node.GetPort

Thor Brigsted edited this page on 13 May 2018 · 2 revisions

给定一个端口的名字,返回对应的端口。搜索所有的端口。

public NodePort GetPort(string fieldName);
ParametersSummary
fieldNameField name of the variable associated with the NodePort.

二十四、Node.GetValue

Thor Brigsted edited this page on 23 May 2018 · 2 revisions

从一个节点的output端口处请求数据,返回的值是该节点在该output处的值。
所有具有outputs端口的节点,都要重新实现该方法。

public override object GetValue(NodePort port);
ParametersSummary
portThe requested port

When a user calls GetInputValue, the value is returned from the connected node’s GetValue method. Override this method to specify what is returned.

当用户调用GetInputValue方法时,得到的值是从连接到该节点的其它节点上传来的,其它节点传来的这个值是用它自己的GetValue方法计算得出。所以说,你需要在GetValue里面实现具体的业务代码。

public class MyNode: Node {
    public float value;
    [Output] public float outA;
    [Output] public float outB;

    public override object GetValue(NodePort port) {
        // Check which output is being requested. 
        switch(port.fieldName) {
            case "outA": return value; // return value
            case "outB": return -value; // return negative value
        }
    }
}

See also: GetInputValue GetInputValues

二十五、Node.HasPort

Thor Brigsted edited this page on 13 May 2018 · 3 revisions

判断端口是否存在:给定一个端口的名字,判断该端口是否存在。端口包括static和instance端口。

public bool HasPort(string fieldName);
ParametersSummary
fieldNameUnique NodePort identifier.

#第二十六章、Node.OnCreateConnection
Thor Brigsted edited this page on 15 Nov 2018 · 2 revisions

当两个节点端口之间创建连接的时候,该方法被调用。

public virtual void OnCreateConnection(NodePort from, NodePort to);
ParametersSummary
fromOutput
toInput

See also: OnRemoveConnection

二十六、Node.RemoveInstancePort

Thor Brigsted edited this page on 23 Jan 2018 · 1 revision

移除节点上的实例端口(动态端口)

public void RemoveInstancePort(string fieldName);
public void RemoveInstancePort(NodePort port);
ParametersSummary
fieldNameUnique identifier used to find this NodePort. Automatically assigns a unique name if null.
portThe instance NodePort to remove

See also: ClearInstancePorts,AddInstancePort

二十七、Node.VerifyConnections

Thor Brigsted edited this page on 13 May 2018 · 1 revision

检查所有的连接是否是有效,存在无效引用的,该连接会被移除。

public void VerifyConnections();

二十八、NodeDataCache

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

在编辑器状态的时候,就预先把反射数据缓存起来,以供运行时阶段使用。

public static class XNode.NodeDataCache

Static Methods

TypeNameSummary
voidUpdatePorts(Node node, Dictionary<String, NodePort> ports)Update static ports to reflect class fields.

二十九、节点编辑器——NodeEditor

Thor Brigsted edited this page on 29 Oct 2018 · 3 revisions

这是所有自定义节点编辑器的基类。用它你可以为自己的节点创建自定义的观察器和编辑器。

public class XNodeEditor.NodeEditor
    : NodeEditorBase<NodeEditor, CustomNodeEditorAttribute, Node>

Methods

TypeNameSummary
voidOnHeaderGUI()Override to draw custom GUI on the node header
voidOnBodyGUI()Override to draw custom GUI on the node body
Int32GetWidth()Override to change the node width
ColorGetTint()Override to tint the node。tint着色的意思
GUIStyleGetBodyStyle()Override to change the node body style
voidInitiateRename()Call to focus and rename this node
voidRename(string newName)Rename the node

Static Fields

TypeNameSummary
ActiononUpdateNodeFires whenever a node was modified through the editor
Dictionary<NodePort, Vector2>portPositionsCached port positions

三十、NodeEditor.OnBodyGUI

Thor Brigsted edited this page on 23 May 2018 · 1 revision

public override void OnBodyGUI();

重写该方法,以便在节点中绘制自定义的GUI。代码类似自定义的inspectors,更多信息请看这里

[CustomNodeEditor(typeof(MyNodeEditor))]
public class MyNodeEditor : NodeEditor {

    public override void OnBodyGUI() {
        EditorGUILayout.LabelField("Text above");
        base.OnBodyGUI();
        EditorGUILayout.LabelField("Text below");
    }
}

See also: GetInputValue GetInputValues

三十一、NodeEditorAssetModProcessor

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

public class XNodeEditor.NodeEditorAssetModProcessor
    : AssetModificationProcessor

Static Methods

TypeNameSummary
AssetDeleteResultOnWillDeleteAsset(String path, RemoveAssetOptions options)

三十二、NodeEditorGUILayout

Thor Brigsted edited this page on 1 Nov 2018 · 3 revisions

public static class XNodeEditor.NodeEditorGUILayout

Static Fields

TypeNameSummary
ActiononCreateReorderableListListen for this event if you want to alter the default ReorderableList

Static Methods

TypeNameSummary
voidPortField(NodePort port, GUILayoutOption[] options)
voidPortField(GUIContent label, NodePort port, GUILayoutOption[] options)
voidPropertyField(SerializedProperty property, Boolean includeChildren = True, GUILayoutOption[] options)
voidPropertyField(SerializedProperty property, GUIContent label, Boolean includeChildren = True, GUILayoutOption[] options)
voidPropertyField(SerializedProperty property, NodePort port, Boolean includeChildren = True, GUILayoutOption[] options)
voidPropertyField(SerializedProperty property, GUIContent label, NodePort port, Boolean includeChildren = True, GUILayoutOption[] options)
voidInstancePortList(string fieldName, Type type, SerializedObject serializedObject, Node.ConnectionType connectionType = Node.ConnectionType.Multiple)Draw an editable list of instance ports. Port names are named as “[fieldName] [index]”

三十三、NodeEditorGUILayout.InstancePortList

Thor Brigsted edited this page on 6 Sep 2018 · 3 revisions

绘制可编辑的动态端口,端口的命名格式为:"[fieldName] [index]"

public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple);
ParametersSummary
fieldNameBase fieldName of the instance ports. If points to the field name of a list, the list will be used as backing values.
typeInstance NodePort value type.
serializedObjectThe serializedObject of the node.
ioWhether this list creates inputs or outputs
connectionTypeConnection type of added instance ports

在这里插入图片描述

定义一个节点class:

// ExampleNode.cs

public class ExampleNode : Node {
    // We will display the list through custom editor, so hide it from the default editor
    [HideInInspector] public List<int> choices;
    
    public override object GetValue(NodePort port) {
        // The instance ports created this way will use the list fieldName and index number, separated by space
        if (port.fieldName.StartsWith("choices ")) {
            int index = int.Parse(port.fieldName.Split(' ')[1]);
            return choices[index];
        }
        return null;
    }
}

为该节点打造一个节点编辑器:

// Editor/ExampleNodeEditor.cs

[CustomNodeEditor(typeof(ExampleNode))]
public class ExampleNodeEditor : NodeEditor {
    public override void OnBodyGUI() {
        // Draw default editor first
        base.OnBodyGUI();
        // Draw list with instance ports
        NodeEditorGUILayout.InstancePortList("choices", typeof(int), serializedObject, NodePort.IO.Output);
    }
}

See also: AddInstancePort,RemoveInstancePort

三十四、NodeEditorGUILayout.PortPair

Thor Brigsted edited this page on 20 Sep 2018 · 2 revisions

在有连接关系的一对端口之间(a pair of ports)绘制连线,比如一个input端口和一个output端口之间有连接关系,那么就在这两个端口之间绘制一根线。

public static void PortPair(NodePort input, NodePort output);
ParametersSummary
input
output
// Editor/ExampleNodeEditor.cs

[CustomNodeEditor(typeof(ExampleNode))]
public class ExampleNodeEditor : NodeEditor {
    public override void OnBodyGUI() {
        // Draw list with instance ports
        NodeEditorGUILayout.PortPair(GetInputPort("myInput"), GetOutputPort("myOutput"));
    }
}

三十五、NodeEditorPreferences

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

节点编辑器的偏好设置

Static Properties

TypeNameSummary
Texture2DcrossTexture
ColorgridBgColor
ColorgridLineColor
BooleangridSnap
Texture2DgridTexture

Static Methods

TypeNameSummary
ColorGetTypeColor(Type type)
voidResetPrefs()

三十六、NodeEditorPreferences

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

public static class XNodeEditor.NodeEditorResources

Static Fields

TypeNameSummary
Styles_styles

Static Properties

TypeNameSummary
Texture2Ddot
Texture2DdotOuter
Texture2DnodeBody
Stylesstyles

Static Methods

TypeNameSummary
Texture2DGenerateCrossTexture(Color line)
Texture2DGenerateGridTexture(Color line, Color bg)

三十七、NodeEditorUtilities

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

public static class XNodeEditor.NodeEditorUtilities

Static Methods

TypeNameSummary
BooleanGetAttrib(Type classType, T& attribOut)
BooleanGetAttrib(Object[] attribs, T& attribOut)
BooleanGetAttrib(Type classType, String fieldName, T& attribOut)
BooleanHasAttrib(Object[] attribs)
BooleanIsCastableTo(this Type from, Type to)
StringPrettyName(this Type type)

三十八、NodeEditorWindow

Thor Brigsted edited this page on 3 Jan 2018 · 1 revision

public class XNodeEditor.NodeEditorWindow
    : EditorWindow

Fields

TypeNameSummary
NodeGraphgraph

Properties

TypeNameSummary
Dictionary<Node, Single>nodeWidths
Vector2panOffset
Dictionary<NodePort, Rect>portConnectionPoints
Singlezoom

Methods

TypeNameSummary
voidControls()
voidCreateNode(Type type, Vector2 position)
voidDrawConnection(Vector2 startPoint, Vector2 endPoint, Color col)
voidDrawConnections()
voidDrawDraggedConnection()
voidDrawGrid(Rect rect, Single zoom, Vector2 panOffset)
Vector2GridToWindowPosition(Vector2 gridPosition)
Vector2GridToWindowPositionNoClipped(Vector2 gridPosition)
RectGridToWindowRect(Rect gridRect)
voidHome()
voidSave()
voidSaveAs()
voidSelectNode(Node node)
voidShowNodeContextMenu(Node node)
Vector2WindowToGridPosition(Vector2 windowPosition)

Static Fields

TypeNameSummary
NodeEditorWindowcurrent
Vector2dragOffset

Static Properties

TypeNameSummary
BooleanisPanning
Dictionary<Type, Color>nodeTint
Type[]nodeTypes

Static Methods

TypeNameSummary
voidBeginZoomed(Rect rect, Single zoom)
BooleanDropdownButton(String name, Single width)
voidEndZoomed(Rect rect, Single zoom)
KeyValuePair2[]`GetContextMenuMethods(Object obj)
Type[]GetDerivedTypes(Type baseType)
Dictionary<Type, Color>GetNodeTint()
Type[]GetNodeTypes()
NodeEditorWindowInit()
ObjectObjectFromFieldName(Object obj, String fieldName)
ObjectObjectFromType(Type type)
BooleanOnOpen(Int32 instanceID, Int32 line)
voidOpenPreferences()
voidRepaintAll()

三十八、NodeGraph

Thor Brigsted edited this page on 3 Jan 2018 · 2 revisions

所有node graph的基类

public abstract class XNode.NodeGraph
    : ScriptableObject

Fields

TypeNameSummary

List nodes All nodes in the graph. See:

Methods

TypeNameSummary
TAddNode()Add a node to the graph by type
NodeAddNode(Type type)Add a node to the graph by type
voidClear()Remove all nodes and connections from the graph
NodeGraphCopy()Create a new deep copy of this graph
NodeCopyNode(Node original)Creates a copy of the original node in the graph
voidRemoveNode(Node node)Safely remove a node and all its connections

三十九、NodeGraph.AddNode

Thor Brigsted edited this page on 13 May 2018 · 2 revisions

在图上增加一个指定type的节点

public virtual Node AddNode(Type type);
ParametersSummary
typeNew Node type.

四十、NodeGraph.Clear

Thor Brigsted edited this page on 13 May 2018 · 1 revision

清除节点图上的所有节点以及所有连线

public void Clear();

See also: AddNode, CopyNode, RemoveNode

四十一、NodeGraph.Copy

Thor Brigsted edited this page on 7 Apr 2018 · 1 revision

拷贝一个图,注意是deep copy

public NodeGraph Copy();

注意:Object.Instantiate(myGraph)这是浅拷贝,graph.Copy()这是深拷贝

using UnityEngine;

public class GraphCopy : MonoBevaviour {

    public MyNodeGraph prefab;

    void Start() {
        // Create a new deep copy of the node graph
        MyNodeGraph copy = prefab.Copy() as MyNodeGraph;

        // Check if a node in the new copy points to the prefab
        if (copy.nodes[0].graph == prefab) Debug.LogError("Referencing prefab");
        else Debug.Log("Referencing new copy");
    }
}```


# 四十二、NodeGraph.CopyNode

Thor Brigsted edited this page on 13 May 2018 · 2 revisions
把图上的某个节点拷贝一份,生成一个新的节点

```csharp
public virtual void CopyNode(Node original);
ParametersSummary
originalNode to make a copy of

See also: AddNode, RemoveNode

四十二章、NodeGraph.RemoveNode

Thor Brigsted edited this page on 13 May 2018 · 2 revisions

安全地移除一个节点,以及与这个节点有关的所有连接

public void RemoveNode(Node node);

See also: AddNode, CopyNode

四十三、NodeGraphEditor

Thor Brigsted edited this page on 30 Sep 2018 · 3 revisions

public class XNodeEditor.NodeGraphEditor
    : NodeEditorBase<NodeGraphEditor, CustomNodeGraphEditorAttribute, NodeGraph>

Methods

TypeNameSummary
Texture2DGetGridTexture()
StringGetNodeMenuName(Type type)Returns the context menu name for given node type. Override this method to modify menu entries. Return null for specified type to hide it from the context menu entirely
Texture2DGetSecondaryGridTexture()
ColorGetTypeColor(Type type)

四十四、NodePort

Thor Brigsted edited this page on 13 May 2018 · 3 revisions

public class XNode.NodePort

Properties

TypeNameSummary
NodePortConnectionReturn the first connection
Int32ConnectionCountNumber of connections to other ports
IOdirectionInput or Output
StringfieldNameThe name of the field
BooleanIsConnectedIs this port connected to anything?
BooleanIsDynamicCreated with AddInstancePort?
BooleanIsStaticCreated with [Input] or [Output] on a field
BooleanIsInputInput port
BooleanIsOutputOutput port
NodenodeNode this port belongs to
TypeValueTypeColor comes from type

Methods

TypeNameSummary
voidClearConnections()
voidConnect(NodePort port)Connect this to another
voidDisconnect(NodePort port)Disconnect this port from another port
NodePortGetConnection(Int32 i)
SingleGetInputSum(Single fallback)Return the sum of all inputs.
Int32GetInputSum(Int32 fallback)Return the sum of all inputs.
ObjectGetInputValue()Return the output value of the first connected port. Returns null if none found or invalid.
TGetInputValue()Return the output value of the first connected port. Returns null if none found or invalid.
Object[]GetInputValues()Return the output values of all connected ports.
T[]GetInputValues()Return the output values of all connected ports.
ObjectGetOutputValue()Return the output value of this node through its parent nodes GetValue override method.
BooleanIsConnectedTo(NodePort port)
voidRedirect(List oldNodes, List newNodes)Swap connected nodes from the old list with nodes from the new list
BooleanTryGetInputValue(T& value)
voidVerifyConnections()Checks all connections for invalid references, and removes them.

四十五、节点[Nodes]

Thor Brigsted edited this page on 21 Aug 2019 · 23 revisions

class Node : ScriptableObject
  • 什么是节点?
    节点就xNode的构建块(building block,简称bb模块)。通过节点类,你可以访问一个节点的端口(ports)以及节点的父图(parent graph)。

你可以用节点编辑器(node editor)来自定义节点的外观。

  • 节点是怎么玩的?
    任何类只要是继承自Node Class,就是一个合法的节点,一旦定义好某个节点,那么graph的上下文菜单中将会出现该节点的名字【在graph中鼠标右键,将会出现创建节点的菜单】。

一个节点,如果它只有一个输入和一个输出,那么它的样子通常如下:

public class SimpleNode : Node {
    [Input] public float value;
    [Output] public float result;
}

节点class中的任何可系列化的字段,你都可以把它变成input或者output端口,秘诀就是给它添加适当的属性,譬如[Input]、[Output]

  • Inputs和Outputs
    节点中的任何可系列化的字段,都可被注册成输入接口(input)或者输出接口(output),方法就是给字典添加[Input]或者[Output]属性。

想知道哪些字段是可系列化的,点这里

想了解关于端口的更多信息,点击这里

两个节点A、B之间有连接关系,节点A向另节点B请求节点B的output值的时候,节点B的GetValue(NodePort port)方法将被调用。你需要为节点B重写GetValue方法,这样才能输出符合实际要求的数据。下面的例子中,GetValue的逻辑就是把input+1然后赋值给output。

// Returns value + 1
public class SimpleNode : Node {
    [Input] public float value;
    [Output] public float result;

    public override object GetValue(NodePort port) {
        // Check which output is being requested. 
        // In this node, there aren't any other outputs than "result".
        if (port.fieldName == "result") {
            // Return input value + 1
            return GetInputValue<float>("value", this.value) + 1;
        }
        // Hopefully this won't ever happen, but we need to return something
        // in the odd case that the port isn't "result"
        else return null;
    }
}
  • Init
    Init方法在节点的OnEnable阶段被调用,也就是说任何时候一旦节点被加载,则该初始化方法就会被调用。这样做的好处就是方便初始化一些non-serialized 的变量。

请记住,Init可能很快就会被弃用,以后您将能够使用常规的OnEnable来代替。

  • Reset
    因为节点都是从ScriptableObject派生的,所以Unity在创建节点时就会调用Reset()。调用Reset发生在Awake和OnEnable之前。如果您想为节点设置一个自定义的名字,那么建议您在Reset里面进行设置。
private void Reset() {
    name = "MyName";
}
  • 小提示
    1、 使用CreateNodeMenu来自定义【创建菜单】的路径
    默认情况下,上下文菜单路径是基于命名空间和类名的。如果您希望更改此create 菜单的路径,可以使用[CreateNodeMenu]属性来设置。只需将其添加到你的类中,并为其指定路径即可。
[CreateNodeMenu("MyMathNodes/Subtraction")]

另外,你也可以把在【创建菜单】中把某个节点的菜单隐藏掉,方法就是把菜单路径字符串设置成空。

[CreateNodeMenu("")]

关于菜单路径的更多信息, 点击node editors

2、 设置节点的颜色[NodeTint]
可以对节点类型进行着色,这样你就可以对节点进行分组和概述。要做到这一点,只需添加一个[NodeTint]属性到你的节点类里,并提供一个十六进制颜色字符串,或3个float表示的rgb数值。

[NodeTint("#ffaaaa")]
[NodeTint(1.0f, 0.8f, 0.8f)]

要了解关于节点着色的信息,点击node editors

3、 设置节点width[NodeWidth]
Sometimes you want a wider node for layout purposes. For this, add the [NodeWidth] attribute to your node class, and supply it with your desired width. The default width of a node is 208 pixels.
有时出于布局的目的,您需要一个更宽的节点。为此,将[NodeWidth]属性添加到你的的节点类中,并为其提供宽度的数值。节点的默认宽度是208像素。

[NodeWidth(304)] 

更多关于节点宽度的信息,点击node editors

4、 节点对[ContextMenu]的支持
节点是支持[ContextMenu] 属性的。简单地添加 [ContextMenu]属性到一个非静态方法上,当你右键单击节点header的时候,将会显示这个菜单。选择这个菜单,它将执行对应的方法。你可以在这里阅读更多相关信息

5、 用[NodeEnum]修复枚举弹出位置

由于GUI缩放有时很奇怪——enum弹出字段在打开时可能会出现偏移。您可以在字段上使用[NodeEnum]属性作为一个简单的修复。

四十五、端口[Ports]

Thor Brigsted edited this page on 10 Dec 2019 · 14 revisions

class NodePort
  • 什么是端口?

端口是节点之间通信的大门,节点是靠端口来联通的。端口可以是输入或输出端口,通过端口,你可找到一个结点的父节点,也可找到一个节点子节点,获取这些信息的方法在端口里面都有定义。
端口通常绑定到一个类型已知的变量,用于定义节点的颜色,以及它可能去连接的其他节点。有的端口是动态的——动态端口

  • 端口怎么用?

Ports can be added by adding either an [Input] or an [Output] attribute to serialized variable. General rule of thumb is; if Unity can serialize it, it can be a port.

添加一个端口的方法——把一个可系列化的字段添加上[Input]或[Output]属性标签。
一般的经验是:如果Unity能够序列化它,它便能够成为一个端口。

有时候你希望动态地添加或者一处一个端口,那么请看动态端口

在一个节点class里面,端口的经典用法如下:
获取被连接的节点:

// Get the connected node.
NodePort otherPort = GetOutputPort("myOutput").Connection
if (otherPort != null) {
  MyNode nextNode = otherPort.node as MyNode;
}

统计一个input端口上,有多少个输入连接

// Get the sum of all number inputs added together
return GetInputPort("myInput").GetInputSum(myInput);
  • 参数
    端口属性也支持一些参数:

Port attributes also support a number of parameters:

backingValue -何时显示backing字段的值。
connectionType -该端口允许的连接数是多少
dynamicPortList - If true, will display a port per list item instead of one port for the entire list
typeConstraint -限制你可以连接到这个端口的值的类型

四十六、Scene Graphs

Thor Brigsted edited this page on 6 Apr 2020 · 1 revision

class SceneGraph : Monobehaviour
  • Scene Graphs是啥?
    Scene graphs are graphs that exist in the scene rather than as an asset. These graphs can reference scene objects, and are not shareable between scenes. Unfortunately do not work in prefabs.

场景图是存在于场景中的图而不是作为asset资源的图。这些图可以引用场景对象,并且不能在场景之间共享。不幸的是,预制件不能使用。

  • 如何使用?
    SceneGraph is a component, and all you have to do is add it to any GameObject. Through the component inspector, you can manage its graph.

SceneGraph lets you add any type of graph to it. If you want to create a more limited version of SceneGraph that only allows a certain type of graph, you can do so by creating a new class and inheriting from SceneGraph where T is the graph type of your choice.

SceneGraph是一个组件,你所要做的就是将它附加到任何游戏对象上。通过组件检查器,你可以管理这些图。
SceneGraph允许你添加任何类型的图到它上面。如果你想创建一个更受限的SceneGraph版本,它只允许某种类型的图形被添加,那么你可以通过创建一个新类并继承SceneGraph,并限定类型T为是你选择的图的类型。

public class MySceneGraph : SceneGraph<MyGraph> { }

四十七、xNode与git

Thor Brigsted edited this page on 11 Sep 2019 · 3 revisions

  1. Install and setup git-fork
    Git-fork is a free and well designed git client for Windows and Mac. While it is possible to use git from command-line I heavily recommend getting a client.

Download and install: https://git-fork.com/

  1. Get xNode into your project
    If your project is already a git repository: Add xNode as a submodule.
    From git-fork, open your project, then right-click Submodules on the left panel and hit Add New Submodule…
    在这里插入图片描述
    In the dialog box that pops up, paste git@github.com:Siccity/xNode.git into the URL field, and set the folder to Assets/Submodules/xNode.

Note: You can use any other folder as long as it’s inside the Assets folder. For example Assets/xNode will work fine as well.

在这里插入图片描述
Once you got that done, hit Add Submodule and you’re done.

If you don’t have your project backed up by git: Clone xNode.
From git-fork, click File/Clone…

在这里插入图片描述
In the dialog box that pops up, paste git@github.com:Siccity/xNode.git into the URL field, and set the parent folder to wherever you want xNode to be. For example, setting parent folder to C:/Unity/MyProject/Assets Assets/Submodules/xNode.

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值