Skip to main content

自定义操作

本文档适用于 CyanTrigger 版本 0.4。如果您使用的是 0.3 或更低版本,请跳至该部分。

CyanTrigger 的自定义操作功能允许用户创建自定义操作、事件,甚至自定义变量类型,从而实现类似“子程序”的功能。这既可以简化常用操作,也可以构建复杂的自动化程序。本文将详细介绍自定义操作的创建、使用和配置。示例部分将提供更直观的理解。

自定义操作指示器

在使用 CyanTrigger 时,用户可能会无意中在逻辑中嵌套多个自定义操作。 可以通过多种方法识别自定义操作:例如,黄色 CyanTrigger 图标通常表示该操作已被自定义。

image.png

事件

对于自定义操作事件,Event Variant 选择器将显示非“VRC_Direct”的名称。此外,Event Header 下会显示“Custom Action Info”部分,包含程序资源文件和自定义操作定义。点击这些信息将直接跳转到 Assets 文件夹中的相关文件。

image.png

image.png

操作

所有自定义操作的名称后均添加星号 (*) 以示区分,从而避免与内置 Udon 操作混淆。此外,自定义操作的名称还会以不同颜色显示,进一步增强其可辨识性。

image.png

要使颜色更醒目,请在“CyanTrigger Settings UI Settings”部分配置颜色。“Udon Type Name”用于内置类型,“Custom Action Name”用于自定义操作。

image.png

展开自定义操作以显示其输入后,"Action Variant" 选择器下会出现“自定义操作信息”部分,其中包含项目资源和自定义操作定义。点击任一项目即可选择“资源”文件夹中的相应文件。

image.png

向事件添加操作时,# 图标表示内置 Udon 操作或代码定义的操作,而黄色 CyanTrigger 图标则表示自定义操作。

image.png

自定义操作实例 (变量类型)

Variables 部分中,所有自定义操作实例名称后都带有星号 (*)。鼠标悬停在截断的变量名称上会显示完整类型名称的工具提示,并提供一个按钮用于查看定义此类型的程序资源文件。

image.png

在添加全局变量时,“自定义类型”部分列出了项目中所有已定义的自定义操作实例,其名称末尾带有“(Custom)”标识。

image.png

创建自定义操作

创建自定义操作前,建议先完成 Udon 程序的开发(可以使用 CyanTrigger、UdonGraph 或 UdonSharp)。 避免在创建后频繁修改程序,以免需要更新所有已使用的自定义操作

创建自定义操作步骤:

右键单击 Assets 文件夹,选择“Create/CyanTrigger/CyanTrigger Custom Action”。这将创建一个带有黄色 CyanTrigger 图标的自定义操作定义文件。

image.png

将 Udon 程序资源文件拖拽到“Udon Program Asset”属性中。

image.png

自定义操作定义选项

image.png

创建并添加程序后,您可以设置以下选项:

默认命名空间 (Default Namespace)

定义自定义操作集合的名称,新添加的操作将自动应用此命名空间。 虽然命名空间并非强制一致,但保持一致性有助于组织代码。 更改默认命名空间会更新所有具有相同命名空间的已定义操作。当 Custom Action Definition 设置为多实例时,默认命名空间将作为 Variables 部分中显示的自定义类型的名称。

自动添加优先级 (Auto Add Priority)

当多个自定义操作设置为自动添加到同一事件时,此选项决定添加顺序。数值越小,优先级越高。

实例类型 (Instance Type)

自定义操作有两种实例类型:单实例和多实例。

    • 单实例: 所有操作共享相同的变量数据,如同只有一个 Udon 程序实例在使用它。适用于无需在两次调用之间保存数据的操作(例如 GameObject.ToggleActive)或所有调用都应使用相同数据的操作(例如 Transform.Respawn)。

    • 多实例: 可以创建多个自定义操作实例,每个实例拥有自己的数据。多实例自定义操作被视为自定义类型,使用时需要在 Variables 部分创建实例并将其关联到操作。有关更多详细信息,请参阅 Counter 示例或 GameObjectSyncedToggle 示例

定义操作

点击操作列表中的加号图标 (+) 可添加操作。

image.png

弹出的菜单列出了程序中的所有事件,以及一个特殊的“Variable Setter”选项,用于仅设置或获取变量值,无需其他逻辑。 注意,某些事件(例如 Start 或 OnDeserialization)可能需要手动添加(点击“自动添加非自定义事件”)。

添加操作后,系统会根据事件类型以不同的方式显示:自定义事件显示为“Action”,其他事件类型显示为“Event”。

EventType 事件类型

在示例中,Start 是唯一的非自定义,将显示在 Events 列表中。

ShowInEventList 中

MyEvent 和 SetMyVariable 都是自定义的,将显示在 Action 列表中。

ShowInActionList 显示

将自定义操作创建为 Event 时,它还必须定义何时应调用其操作。要定义此项,请在事件中的某个位置添加 UdonBehaviour.SendCustomEvent 操作。确保 UdonBehaviour 以自身为目标,如果使用 CyanTrigger,则为 This UdonBehaviour,并且事件为空或 null。

EventCallActionsDirect

此示例将在启动时立即调用操作,而不执行任何其他操作。您还可以添加有关何时或是否应触发操作的逻辑。

EventCallActionsMaster 事件调用操作大师

在此示例中,它会检查本地用户是否是实例的主用户,并且只有当他们是主用户时,才会触发操作。

操作选项

添加操作后,您可以设置以下选项:

自动添加操作 (Auto Add)

启用后,此操作将自动添加到 CyanTrigger,并在列表中隐藏。所有变量将设置为隐藏并使用默认值。 如果多个自定义操作对同一事件设置了自动添加,请使用自动添加优先级来确定添加顺序。

操作命名空间 (Action Namespace)

搜索操作时显示的名称,建议与默认命名空间保持一致。

操作变体名称 (Action Variant Name)

此操作的名称,命名时需谨慎避免冲突。

描述 (Description)

对操作功能的描述(目前未在界面中显示)。

基本事件名称 (Base Event Name)

Base Event Name 用于内部目的,但显示在 Inspector 中。它列出了此操作的事件类型。如果程序本身中的事件类型发生更改,则可以使用 “Edit Base Action Data” 选项来更新此事件。请谨慎执行此操作,因为更改此项可能会破坏操作本身。

活动入口 (Event Entry)

Event Entry 用于内部目的,但显示在检查器中。它列出了此操作的事件的编译名称。如果程序本身的事件名称或类型发生更改,则可以使用 “Edit Base Action Data” 选项来更新此事件。请谨慎执行此操作,因为更改此项可能会破坏操作本身。

定义操作输入

image.png

定义 Action 后,您还可以定义此操作的输入。这些输入将影响在 CyanTrigger 中使用此操作时显示的输入。将操作添加到自定义操作定义时,它将以无变量开始,或者如果操作有参数,则显示该操作的所有参数。在此示例中,MyCustomAction 有一个将自动添加的参数。使用参数时,某些选项将被禁用,因为该值由参数本身设置。如果程序中的参数被修改过,则需要使用顶部的 “Edit Base Action Data” 复选框手动更新此自定义操作。有关更多详细信息,请参阅更新自定义操作

image.png

Udon 名称 (Udon Name)

程序中变量的名称,必须完全匹配。 对于 CyanTrigger 参数,格式应为 arg(VariableName)_(EventName)

显示名称 (Display Name)

在操作检查器中显示的输入名称。

描述 (Description)

对输入用途的描述,鼠标悬停在检查器中的变量上时显示。

image.png

在检查器中隐藏 (Hidden in Inspector)

隐藏输入,始终使用默认值。启用后,“对多个对象重复”和“修改变量”选项将被禁用。

对多个对象重复 (Repeat for Multiple Objects)

允许在一次操作中对多个对象应用相同的操作。仅第一个输入可用此选项。

image.png

修改变量 (Modifies Variable)

类似于 Custom Event 参数的 Output 选项。 取消选中后,允许直接输入或使用变量输入。 选中后,预期自定义操作会修改变量值,并将修改后的值同步到检查器中使用的变量。

image.png

默认值 (Default Value)

在检查器中初始化的值。如果选中“在检查器中隐藏”,则始终使用此值。 如果选中“修改变量”,此字段将被禁用。

更新自定义操作

建议避免修改程序中使用的事件和变量。如果必须修改,请选中“Edit Base Action Data”复选框来更新自定义操作中的相关信息。这通常是未选中的,因为在不知道的情况下修改这些值会破坏自定义操作。选中此选项后,您可以编辑以下项目:

  • 操作基事件名称
  • 操作进入事件
  • Action Input Udon Name
  • Action Input Parameter 修改变量
  • Remove Action 输入参数

image.png

自定义操作示例

GameObject.ToggleActive

ExampleGameObjectToggleActive

CyanTrigger 提供了一种名为 GameObject.ToggleActive 的默认自定义操作。该操作由一个简单的 CyanTrigger 程序实现,该程序包含一个 GameObject 类型的全局变量和一个自定义事件。此事件获取该全局变量的活动状态,将其反转,然后重新设置。由于这是一个自定义事件而非系统事件,因此它被视为一个 Action(动作)。

根据自定义操作定义,仅定义了一个操作,该操作位于 GameObject 命名空间下,使其与其他 GameObject 操作一起显示。其名称为 ToggleActive,与程序中的事件名称不同。该操作包含一个变量输入,对应于程序中的 GameObject 全局变量。 它支持对多个对象重复执行,从而允许用户在一个操作中同时应用于多个对象。

这种自定义操作是极其简单的示例之一,它本质上是对多个操作的简化封装。

ExampleGameObjectToggleActiveUse

OnPlayerTriggerEnter.LocalPlayer

ExamplePlayerTriggerEnterLocal

CyanTrigger 的默认自定义操作之一 OnPlayerTriggerEnter.LocalPlayer 由一个简单的 CyanTrigger 程序构成,该程序包含一个基于 OnPlayerTriggerEnter 事件的触发器。由于并非自定义事件 (Custom Event),该触发器在使用时会被视为标准事件 (Event)。

程序逻辑如下:它检查触发器内玩家的身份。如果是本地玩家,则向自身发送一个空事件,此空事件在自定义操作 (Custom Actions) 中指示执行 CyanTrigger 事件关联的动作。若触发器内的玩家并非本地玩家,则程序不会执行任何操作,从而避免对远程玩家触发动作。

其自定义操作定义 (Custom Action Definition) 仅包含一个操作,该操作位于 OnPlayerTriggerEnter 命名空间下,使其在 VRChat 中与 OnPlayerTriggerEnter 事件一同显示。该操作命名为“本地玩家 (Local Player)”,并在事件头 (Event Header) 中作为可选变体出现。该操作不接受任何变量输入。

ExamplePlayerTriggerEnterLocalUse

Transform.Respawn (变换.重生)

ExampleTransformRespawn (示例变换重生)

Transform.Respawn 是一个自定义操作,用于展示 Auto Add 功能。该程序包含两个操作:StartRespawnStart操作记录变换的初始位置和旋转。Respawn操作则将变换恢复到初始位置和旋转,并移除刚体(如有)的所有速度。

与之前的示例不同,本程序需要初始化,并在两次调用之间保存状态信息。为此,程序设计为两个独立的操作:Start操作用于初始化自定义操作,Respawn操作允许用户重置变换。通过将Start操作设置为“自动添加”,用户只需使用Transform.Respawn自定义操作即可自动触发Start操作的初始化过程,无需手动添加Start操作。 “自动添加”的操作不会出现在用户可添加操作的列表中。

ExampleTransformRespawnUse

您只需在 CyanTrigger 中的任何位置添加此操作,一切即可正常工作。

计数器

Counter 是一个简单的示例,展示了 Custom Actions 中的多实例支持。此自定义操作定义了一个计数器,您可以向该值添加一个计数器,然后检查该值是否“很大”。

ExampleCounter

查看该程序,有一个变量来保存 counter 值,一个事件将该变量的值加 1,然后如果该值被视为 “large” ,则返回一个事件。在这种情况下,large 仅表示大于 10。

ExampleCounterUse

在此示例中,使用 Custom Action,在 variables 部分中定义了两个计数器:redCounter 和 blueCounter。已创建两个事件以添加到每个计数器,然后检查该计数器是否为 “Large”。如果值很大,请打印出它很大。此示例本身可能没有意义,但它显示了定义处理数据的方法的构建块。

GameObjectSyncedToggle

GameObjectSyncedToggle 是一个示例,展示了自定义操作中的多实例支持。与其他示例相比,这是一个复杂的示例。Multi-Instance 类似于创建自己的 Variable Types,是一种子程序形式,它期望为自定义操作的每个“实例”保存数据。在此示例中,Custom Action 将保存游戏对象和同步的布尔值,并允许操作切换布尔值,这将自动设置已保存游戏对象的启用状态。

SyncedToggleExampleProgram

查看程序,在 variables 部分中声明了两个保存的值,其中“isEnabled”是同步的布尔值,“syncedGameObject”是将切换状态的对象。

  • “_SetGameObject”事件采用一个游戏对象参数,该参数将更新变量并更新“isEnabled”变量的值(在屏幕截图中省略)
  • “_Toggle”事件将确保本地玩家是持有此操作的游戏对象的所有者,翻转同步的“isEnabled”变量的值,然后请求 Udon 将变量同步到房间中的每个人。
  • 最后,每当值更新时,都会调用检查 “isEnabled” 布尔值的 OnVariableChanged 事件,并为保存的游戏对象设置启用状态。

SyncedToggleExampleDefinition

查看 Custom Action Definition,这里的主要项目是 “Instance Type” 设置为 “Multi-Instance”。有了这个,你可以在 CyanTrigger 的 Variables 部分创建自定义操作的 “实例”。有 2 个定义的操作链接到具有相同名称的程序。

SyncedToggleExampleUse

在这里,您可以看到使用 GameObjectSyncedToggle 自定义操作的 CyanTrigger。它在 variables 部分有两个实例:“syncedToggle1”和“syncedToggle2”。在 start 方法中,它为两个实例调用 SetGameObject,每个实例都有不同的对象。使用 “Multi-Instance” 自定义操作时,您必须选择要用于每个操作的实例。

SyncedToggleExampleUseInstance

初始化两个实例后,有两种方法可以单独切换每个实例。“Toggle1” 将切换 “syncedToggle1” 实例,“Toggle2” 将切换 “syncedToggle2” 实例。

SyncedToggleExampleUseHierarchy

V0.3 自定义操作

本节内容仅适用于 CyanTrigger 0.3 及以下版本。如使用 0.4 或更高版本,请参考相关章节。CyanTrigger 允许创建自定义操作,但此功能尚在开发中,部分功能尚未实现。更多细节请参见“限制”和“注释”章节。

目前,自定义操作只能基于已有的 Udon 程序执行。建议使用 UdonGraph 或 UdonSharp 替代 CyanTrigger。所有 CyanTrigger 附带的自定义操作均在 UdonGraph 中实现,其源代码位于 “Assets/CyanTrigger/Resources/DefaultCustomActions” 文件夹下,供用户参考。

创建自定义操作

您可以为事件 (Events) 和操作 (Actions) 创建自定义操作。基于 CustomEvent 的事件将显示在“操作”列表中;其他类型的事件则显示在“事件”列表中。创建事件自定义操作时,必须包含至少一个 SendCustomEvent 节点,且流程无输入。此节点将被 CyanTrigger 操作替换。

建议您先创建并完成 Udon 程序,再定义 CyanTrigger 自定义操作。准备好 Udon 程序后,右键单击您的资源文件夹,选择“创建/VRChat/CyanTrigger/CyanTrigger 自定义 Udon 操作”即可创建新的自定义操作定义。这将生成一个基于 Udon 的自定义操作。将 Udon 程序拖放到属性面板中即可进行编辑。

定义操作

要创建 Udon 程序的自定义操作,请点击“操作”列表中的加号按钮。这将显示 Udon 程序中所有事件的列表,并允许您为同一事件创建多个自定义操作。此功能在使用 CyanTrigger 界面中隐藏的默认变量时尤其有用。

添加操作后,请为其选择命名空间。命名空间决定此操作在“操作”和“事件”列表中的显示位置。使用相同命名空间的操作将分组显示。此外,还需为操作指定变体名称,这相当于方法名,应简明扼要地描述操作的功能。

定义操作输入

定义 Action 后,您还可以编辑此自定义操作的 Inputs。Variables (变量) 列表将显示此操作的输入。变量只能使用一次。变量的选项是 Udon 程序中的 Public 变量。每个变量都有一些设置:

  • Udon 名称 (Udon Name): 这是 Udon 程序中使用的变量名称。请勿修改此名称,以免破坏与 Udon 程序的关联。
  • 显示名称 (Display Name): 此名称将在 CyanTrigger 界面中显示。 请使用清晰、具有描述性的名称。
  • 描述 (Description): 对该变量的详细描述。此描述将作为工具提示显示在 CyanTrigger 界面中显示名称的下方。
  • 对多个对象重复 (Repeat for Multiple Objects): 此选项仅对列表中的第一个输入项可用。启用此选项后,CyanTrigger 检查器将为该输入创建一个列表。 该操作将对列表中的每个项目执行。
  • 在 Inspector 中隐藏 (Hide in Inspector): 此选项仅适用于已设置默认值的常量。通过此功能,您可以创建操作的不同预设版本。
  • 允许常量 (Allow Constant): 启用此选项后,可以在 CyanTrigger 界面中使用常量值。 但并非所有数据类型都支持常量编辑器。
  • 允许变量输入 (Allow Variable Input): 启用此选项后,可以使用变量作为该自定义操作的输入。
  • 修改变量 (Modify Variable): 选中此选项表示 Udon 程序将修改此变量。如果选中,Udon 程序中对变量的任何更改都将同步到界面中提供的输入变量。如果用户提供的变量具有 OnValueChanged 回调函数,则会在自定义操作完全完成后触发该回调。 未选中此选项且 Udon 程序修改了变量时,CyanTrigger 界面中提供的变量将不会发生变化。
  • 默认值 (Default Value): 当允许使用常量值时,此字段指定默认值。
局限性

自定义操作系统仍处于开发初期。您可以创建的程序类型存在限制。这些将来可能会发生变化。

  • 状态单一性限制了变量的独立性。所有使用同一 CyanTrigger 的自定义操作实例都共享相同的变量。若未在 Inspector 面板中显式设置,则使用上一次操作的变量值。这意味着,如果自定义操作包含递增变量,则该变量在该 CyanTrigger 上的所有操作中都将保持一致,目前无法为每个自定义操作实例提供唯一的变量。
  • 事件机制仅支持单一自定义操作。 如果需要依赖其他操作或数据,必须将其定义为独立的自定义操作,并手动添加到 CyanTrigger 中。这增加了操作的复杂性和维护成本。
笔记
  • 虽然一个 Udon 程序和自定义操作定义中可以定义多个操作,但最佳实践是每个 Udon 程序只定义一个操作。这是因为 Udon 程序的整个程序集会被复制到 CyanTrigger 中,未使用的操作会增加 CyanTrigger 程序的大小。
  • CyanTrigger 自定义操作定义文件不会被复制。每个已定义操作都具有唯一的 GUID 标识符。复制定义文件无法正确生成新的 GUID。
  • 定义自定义操作后,请勿更改程序源代码中的操作名称。更改自定义事件名称、替换为其他事件或更改公共变量名称都可能导致定义无法正确更新,从而引发问题。然而,您可以更新程序中的节点。

 

例子

操作示例

这是 GameObject.ToggleActive 的自定义操作。该操作在 UdonGraph 中使用自定义事件 (Custom Event) 实现,并定义了两个公共变量。在 CyanTrigger 自定义操作定义中,只有一个操作,它仅使用其中一个公共变量作为输入。 该公共变量可以是常量或变量,允许在操作的多个实例中重复使用,且操作不会修改该变量的值。

事件示例

这是 OnTriggerEnter.GameObject 的自定义操作。该操作在 UdonGraph 中使用 OnTriggerEnter 事件实现,并定义了一个公共变量。 值得注意的是,流链中的最后一个节点为 SendCustomEvent,且无输入。对于事件自定义操作 (Event Custom Actions) 而言,此节点至关重要,因为它触发 CyanTrigger 操作的执行。 如果需要在所有操作执行后添加更多逻辑,可以在 SendCustomEvent 节点之后添加相应的节点。 在 CyanTrigger 自定义操作定义中,只有一个操作,它使用一个公共变量作为输入。 与第一种操作类似,该公共变量可以是常量或变量,允许在操作的多个实例中重复使用,且操作不会修改该变量的值。