可视化节点编辑器Node Editor Framework——构建扩展

本文参考自https://nodeeditor.seneral.dev/Documentation/Extensions.html

帮助用户使用框架Node Editor Framework构建自己的节点编辑器

构建扩展

此页面将指导用户创建自己的扩展基于此框架的完整工具。 其中大部分是通过动态获取新内容(如节点和其他类型规范)来实现的。

 另一方面,如果用户直接需要修改框架本身,请参阅框架概述以了解每个框架部分的工作原理。

自定义节点

创建自定义节点是每个扩展的核心步骤。它允许用户向图形中添加新功能。幸运的是,这也很容易做到!

当用户想要编写一个节点脚本扩展NodeEditorFramework时,用户自定义的节点类必须继承自Node,因为Node类提供了框架所需基本功能用户通过对继承自Node类的可选属性进行赋值,来决定该节点如何在编辑器中显示,从而定制一个新节点。

节点可以放置在项目中的任何位置,因为框架可以从所有标准脚本程序集中动态获取所有节点实体。

这也意味着,即使框架是用C#编程的,用户也可以在UnityScript中添加节点,但有一个限制,即它们必须在第2、3或4阶段进行编译,如下所述。因此,节点实体是用独立的语言描述的。

以下列表简述了必要的节点成员。用户可以从'Plugins/Node_Editor/Nodes/Example'中找到的ExampleNode引用。

这仅适用于开发分支中的新系统!

使用命名空间NodeEditorFramework

派生类MyMode继承自NodeEditorFramework.Node

可选的Node属性:(hide?,contextPath, [limitToCanvasType])

唯一的节点ID:定义为const ID, 通过override GetID实现外部访问

可选的可重写行为选项

        string Title = [Class Name]                    // 指定节点的标题

        Vector2 DefaultSize = (200, 100)          // 指定AutoLayout关闭时默认的节点大小

        bool AutoLayout = false                         // 指定节点是否自动调整大小以适应内容

        Vector2 MinSize = (100, 50)                // 指定节点的最小大小

        // 指定此节点是否处理递归节点循环。对于一个循环,至少需要一个节点来处理它。

        bool AllowRecursion = false         

        //指定在成功计算此节点后是否应继续计算。连接端口定义(更多信息见下文)与指定端口属性的类型相对应的属性。用于保存在相应属性中定义的端口的实际变量。       

        bool ContinueCalculation = true        

方法protected override void OnCreate

方法 public override void NodeGUI

        使用GUILayout/EditorGUILayout/RTEditorGUI函数 绘制节点GUI并访问属性以进行编辑。

        使用DisplayLayout/SetPosition函数显示连接端口/设置连接端口的位置

方法public override bool Calculate

        使用connected/GetValue函数 在用户的输入端口上获取它们的状态和值。

        使用SetValue函数在输出端口上设置其计算值。

        如果出现问题,返回false,否则返回true!

连接

注意:以下内容在最新的develop分支中进行了重大修改,不再适用于master分支!

连接类型

理解连接类型的层次结构对于理解连接的创建和样式非常重要。

基本上,层次结构允许根据连接类型(如转换)的需要和未来扩展计划来抽象特性。

对于这些连接类型中的每一种,实际上有两个以上的类遵循相同的层次结构:属性和样式。

        ConnectionPort

                此类是节点的通用端口,能够连接到其他节点的其他端口。

                此类定义了名称(不能为空),以及可选的样式ID、方向和最大连接数。

                注意!此类没有定义位置、功能或任何相关特性

                属性:ConnectionPortAttribute

                样式:ConnectionPortStyle

                ConnectionKnob : ConnectionPort

                       节点侧面的旋钮,能够连接到其他节点上的其他旋钮,前提是它们具有相反的方向。

                        另外定义节点侧和该节点侧的位置。同时(当前)强制执行方向的规范。

                        注意!此类没有定义旋钮的用途

                        属性:ConnectionKnobAttribute

                        样式:ConnectionKnobStyle

                                ValueConnectionKnob : ConnectionKnob

                                        位于节点一侧的特定类型的旋钮,能够连接到其他节点上类型相同且方向相反的其他旋钮。

                                        另外还定义了一个类型(不能为空),作为旋钮的用途,用于将值从一端传递到另一端。

                                        属性:ValueConnectionKnobAttribute

                                        样式:ValueConnectionKnobStyle

在大多数情况下,用户需要使用ValueConnectionKnob,它允许用户实际通过连接传递值。

属性指定特定ConnectionPort的详细信息,并用于创建。

样式可以扩展为预定义样式(或者在 ValueConnectionKnob 的情况下,类型),在创建时通过它们的 styleID 传递给属性。

基本上,在所有情况下,相应的类都不能跨越层次结构级别进行交互,这意味着用户不能将ConnectionPortStyle用于ValueConnectionKnob定义,因为它缺少创建ValueConnectionKnob(如类型)的重要信息。

连接端口的创建

现在,如上所述,要在节点中创建新的ConnectionPort,需要将其声明为普通字段,并对其应用相应的特性,指定所有必需(或可选)信息。

[ValueConnectionKnob("Input", Direction.In, "Float")]

public ValueConnectionKnob inputKnob;

框架根据用户在属性中指定的信息自动创建旋钮。

此属性还可用于 手动/自动 创建旋钮,使用设计函数(例如,请参阅ResizingNode)。

这里使用的styleID“Float”是标准框架的一部分,其定义如下:

自定义节点画布

注:本节内容未完成!此功能也可能尚未达到其最后阶段,仅在开发分支上可用!

如果需要完全控制画布的生命周期、可用节点或对节点使用方式的限制,可以创建自定义节点画布类型以手动驱动某些功能。除此之外,用户还可以为画布创建自定义遍历例程。

默认遍历例程以普通的左右方式计算节点,但如果需要,可以完全替换。

实现

有关自定义NodeCanvas类型的实现指南,请参阅NodeCanvas类和以下示例。

在核心部分,创建自定义NodeCanvas的工作方式与创建自定义节点的工作方式相同,框架动态获取所有NodeCanvas类型并将它们呈现给用户。另一方面,NodeCanvasTraversal不是由框架处理的,而是由canvas实现本身处理的。

画布的最简单形式是原生的CalculationCanvaType,它没有其他规则或限制。

另一方面,原生的GraphCanvaType有一个专用的遍历系统,还确保始终只有一个根节点。

在分支Examples/Dialogue System中可以找到更复杂的自定义NodeCanvas示例。

自定义输入控制

对于编辑器扩展,用户可能希望在单击画布和编辑器时 触发自定义的上下文,即添加自定义的控件和回调函数。

使用动态输入系统很容易做到这一点,只需使用提供的四个属性即可应用于静态处理程序函数。

在详细解释这些之前,可能值得说明一下NodeEditorInputControls中的默认控件!

主信息容器——NodeEditorInputInfo包含事件有关的所有信息,包括编辑器状态、鼠标位置和调用事件。它用于向动态输入处理程序提供所有必要的信息。

以下事件属性使用优先级概念,这是一个可选参数。它主要定义执行顺序,从最低值(小负数)到100。

指定大于100的值将在处理GUI后执行输入,以确保它不会阻塞UI。

EventHandler属性

EventHandlerAttribute用于处理节点编辑器的任意事件,是最灵活的属性。某些默认控件(如节点拖动、平移、缩放和节点连接)只能使用此属性实现。

使用此属性标记静态函数可在指定的“EventType”发生时(或始终在未指定事件时)调用该函数。

方法特性必须如下:[ Return: Void; Params: NodeEditorInputInfo ]

Hotkey 属性

HotkeyAttribute用于为节点编辑器的热键提供一个简单的接口。一些默认控件,如导航('N')和捕捉('Control')是使用此属性实现的。它允许用户指定KeyCode/EventModifier与限制EventType的组合,以指定何时调用标记的静态函数。

方法特性必须如下:[ Return: Void; Params: NodeEditorInputInfo ]

ContextEntry 属性

ContextAttribute用于注册NodeEditor的上下文条目。选择指定路径上的上下文元素时,将调用标记函数。

在其中,要添加此元素的上下文菜单由类型指定,如节点上下文单击或画布上下文单击。

方法特性必须如下:[ Return: Void; Params: NodeEditorInputInfo ]

ContextFiller 属性

ContextFillerAttribute用于以动态、有条件或过程的方式在节点编辑器中注册上下文条目。

将调用此函数以任何方式填充传递的上下文GenericMenu。类型再次指定要填充的上下文菜单。

方法特性必须如下:[ Return: Void; Params: NodeEditorInputInfo, GenericMenu ]

自定义编辑器

所提供的编辑器窗口用作所有普通扩展的默认节点画布资源管理器,在大多数情况下工作得非常好。

但是,为了使用户的扩展脱颖而出或实现自定义功能,用户可能需要构建自己的编辑器接口

下面概述了在运行时和编辑器中建立基本节点编辑器界面时要考虑的最重要的事情。

实际上,用户可以使用或替换两个不同的实体,具体取决于用户要自定义的程度。NodeEditorInterface(帮助构建接口)和NodeEditorUserCache(负责存储和缓存画布)。

编辑器画布存储

编辑器必须存储NodeCanvas及其NodeEditorState,并对其进行适当的管理。有关这些的详细说明,请参阅框架概述。

NodeEditorUserCache是一个类,用于帮助扩展管理画布和编辑器状态。它处理画布的存储、保存/加载和缓存。在大多数情况下,用户甚至不需要编辑它,除非用户想更改标准的保存行为。查看NodeEditorWindow或RTNodeEditor,了解如何使用它。

编辑器GUI&接口

首先,需要将 OverlayGUI.StartOverlayGUI / OverlayGUI.EndOverlayGUI and NodeEditorGUI.StartNodeGUI / NodeEditorGUI.EndNodeGUI包装在GUI代码周围,以使自定义弹出窗口正常工作并使GUI看起来统一。

在绘制画布视图之前,请确保已加载画布并将矩形区域指定给NodeEditorState.canvasRect

然后,为了解释可能抛出的错误,将以下绘图函数嵌入一个try-catch块中,该块在抛出错误时卸载画布。但是,请确保只捕获UnityException,因为Unity错误,所有选择器(如ColorField、CurveField或ObjectField)在系统中都会抛出错误。异常-尝试捕获块。

在这个try-catch块中,用户可以安全地调用NodeEditor.DrawCanvas,传递NodeCanvas和EditorState,以便在指定区域绘制画布。

最后,用户可以滚动自己的代码或使用共享的NodeEditorInterface类,为自己修改接口。

这允许用户为画布快速创建控件,如工具栏或模式面板(仅在“开发”分支中)。它们的使用非常简单,请再次参考NodeEditorWindow或RTNodeEditor。

自定义GUI皮肤

目前,节点的GUI皮肤只能通过修改NodeEditorGUI源文件或替换纹理来更改。

对于未来,计划对GUISkin进行更广泛和独立的控制。

事件&回调函数

该框架支持一系列事件集合,它们在编辑过程中可能很重要。这些事件可以通过订阅NodeEditorCallbacks类中的适当委托来接收,也可以通过从NodeEditorCallbackReceiver(这是一种单行为)扩展并重写适当的方法来接收。这两个类都可以在NodeEditorCallbackReceiver中找到

  • OnEditorStartup:节点编辑器启动(切换场景或播放模式时也可能发生)
  • OnLoadCanvas(NodeCanvas):传递的画布已作为副本加载
  • OnLoadEditorState(NodeEditorState):传递的editorState已作为副本加载
  • OnSaveCanvas(NodeCanvas):传递的画布已保存为副本
  • OnSaveEditorState(NodeEditorState):传递的editorState已另存为副本
  • OnAddNode(节点):已创建或复制传递的节点
  • OnDeleteNode(节点):传递的节点将被删除
  • OnMoveNode(Node):传递的节点已被用户移动
  • OnAddConnectionPort(ConnectionPort):已动态添加ConnectionPort。
  • OnAddConnection(ConnectionPort,ConnectionPort):在两个端口之间创建了一个新连接。
  • OnRemoveConnection(ConnectionPort,ConnectionPort):两个端口之间的连接将被删除。

注: ->某些特定于节点的回调也可以通过重写适当的方法从节点直接访问。

->用户始终可以实现其他回调或请求实现它们!

猜你喜欢

转载自blog.csdn.net/qq_39915907/article/details/119647977
今日推荐