Skip to main content

Udon 示例场景

此场景包含世界如何使用 Udon 的示例。您可以构建和测试或发布此世界在 VRChat 中体验。

预制体​

此场景中的预制体演示了与 VRChat 组件的常见交互,包括按钮、Avatar 基座、站点、镜子等。

以下所有预制体都包含在 VRChat Worlds SDK 中。您可以将它们添加到任何自己的世界中。例如,VRCWorld 默认包含在大多数 VRChat 场景中。

UdonExampleScene

VRCWorld​

此预制体让您轻松将 Unity 场景上传到 VRChat。它有四个组件:

如果要在自己的 Unity 场景中使用 VRCWorld 预制体,可以在 \Packages\com.vrchat.worlds\Samples\VRCPrefabs\VRCWorld.prefab 中找到。

AvatarPedestal​

这是一个预制体,具有在用户与基座交互时切换 Avatar 的程序,这是预制体的默认行为。

要更改预制体的交互距离,请解包预制体并更改 Udon Behaviour 组件的 "Proximity" 设置。

VRCChair3​

这是一个预制体,具有名为 StationGraph 的程序。当玩家与之交互时,会将玩家安置在站点中,并在进入或退出时记录其显示名称。

MirrorSystem​

此对象上有一个 ToggleGameObject 程序,使用 Interact 事件在活动/非活动之间切换目标对象。在本例中,它控制作为其子对象的 VRCMirror 对象。

立方体​

这些对象演示了可以使用立方体做的一些简单操作,主要是重用 ChangeMaterialOnEvent 程序来展示如何从其他对象触发自定义事件。

Cube Examples

InteractCube​

此对象上有一个 SendEventOnInteract 程序——监听 Interact 事件,当玩家指向对象并按下使用按钮时触发。在本例中,它向子对象上的 ChangeMaterialOnEvent 程序发送名为 "changeMaterial" 的自定义事件,每当收到此事件时,该程序会从数组中切换材质。这两个程序都是可重用的——您可以在 UdonBehaviour 组件的检查器中更改从 SendEventOnInteract 程序发送的 eventName。

TimerCube​

此对象上有一个 SendEventOnTimer 程序——运行一个给定 duration 的计时器,然后发送指定的事件。在本例中,它向子对象上的 ChangeMaterialOnEvent 程序发送名为 "changeMaterial" 的自定义事件,每当收到此事件时,该程序会从数组中切换材质。这两个程序都是可重用的——您可以在 UdonBehaviour 组件的检查器中更改从 SendEventOnTimer 程序发送的 eventName,并更改其 duration(秒)来改变触发频率。

UseCube​

此对象的 Model 子对象上有一个 SendEventOnUse 程序——当对象被拾取并使用"Use"时发送事件。在本例中,它向 MaterialChanger 对象上的 ChangeMaterialOnEvent 程序发送名为 "changeMaterial" 的自定义事件,每当收到此事件时,该程序会从数组中切换材质。这两个程序都是可重用的——您可以在 UdonBehaviour 组件的检查器中更改从 SendEventOnUse 程序发送的 eventName。Model 对象还有一个 VRCObjectSync 组件,用于在移动时将此对象的运动同步给其他用户。

Udon 变量同步​

这些对象演示了从对象的所有者向实例中其他人同步变量值的不同方式。 Udon Variable Sync Examples

"Canvas" 项目有许多带有同步变量的 UI 项目:

ButtonSyncOwner​

这是此处描述的第一个使用手动同步方法的程序。 在下面的图片中,您可以看到它有一个 OnClick() 处理程序,调用 UdonBehaviour.SendCustomEvent,值为 "OnClick"。它针对其下方的 UdonBehaviour,在那里运行自定义事件 "OnClick"。这就是 UI 元素在 UdonBehaviour 上运行事件的方式。

Triggering Custom Events from Unity UI controls

在 Graph 程序中,OnClick 事件检查点击的玩家是否是对象的所有者。如果是,它将 "clickCount" 变量增加 1,然后调用 RequestSerialization,通知 Udon 更新此手动同步的 UdonBehaviour 上的数据。

OnClick ▸ If Owner ▸ Set clickCount to clickCount + 1 ▸ Serialize.

注意 'Set clickCount' 节点开启了 'sendChange' 切换开关。当所有人收到新的 clickCount 值时,这将触发一个事件。

Variable Change events are very powerful! You can use them to run the same logic on the owner and others whenever a synced variable is changed.

当 clickCount 更新时,此更改事件触发,无论谁是这个程序的'所有者',都会将按钮文本设置为新值。

ButtonSyncAnyone​

此对象使用的程序与上面的 ButtonSyncOwner 非常相似,但为点击按钮且不是对象所有者的用户添加了逻辑。在这种情况下,他们向对象的所有者发送自定义事件 "OnClick"。 仅此而已!所有者将收到此事件,并像自己刚刚点击按钮一样处理它。

Non-Owners will send an event to the Owner to easily update the number.

ButtonSyncBecomeOwner​

此对象基于已熟悉的 ButtonSync 程序构建,演示如何轻松更改对象的所有权。当非所有者点击按钮时,会分配他们所有权,然后更新变量。 当您想更改多个变量或执行比简单递增值更复杂的逻辑时,这很有用。 ButtonSyncBecomeOwner

更改对象所有权时,会运行一些逻辑来决定是否允许转移。您可以在此了解更多信息:网络。 如果不添加任何自定义逻辑,所有所有权请求都将被批准。下面的节点展示了一个简单设置,检查名为 'someSpecialLogic' 的布尔变量来决定是否批准转移。您可以根据 'requester'、'newOwner' 或两者构建自己的逻辑。

Does someone want to be the new owner? Check 'someSpecialLogic' that you've updated elsewhere.

SliderSync​

SliderSync

此对象有一个名为 SliderSync 的程序,其工作方式类似于 ButtonSyncBecomeOwner。 当有人移动滑块时,他们成为所有者,并向其他人发送新值。一个区别是,当从 UI 触发 "OnValueChanged" 事件时,它会检查这个新值是否与滑块的当前值不同。这是因为从 Udon 更新滑块的值也会触发此事件,导致无限循环。因此,我们有一些逻辑确保 'sliderValue' 变量与滑块的值不同,然后再运行其余逻辑。

它还使用变量更改事件在有人成为所有者并更新时,用滑块的值更新文本字段。

Toggle​

此对象有一个名为 ToggleSync 的程序,其工作方式与上面的滑块相同。当有人将值更改为与当前值不同的内容时,他们成为所有者,并向其他人发送新值。 Toggle

Dropdown

此对象有一个名为 DropdownSync 的程序,其工作方式与上面的 Toggle 和 Slider 相同。当有人更改值时,他们确保与当前值不同,然后成为所有者并向其他人发送新值。

InputField​

InputField

此对象有一个名为 InputFieldSync 的程序,其工作方式与上面的 Dropdown 类似。当有人更改值时,他们检查是否不同,然后成为所有者并向其他人发送新值。

PickupCube​

PickupCube

此对象具有 VRC Pickup 和 VRC Object Sync 组件,使其能够被拾取和移动,并自动同步给其他用户。UdonBehaviour 设置为 "Continuous" 而不是像上面的同步程序那样使用 "Manual",因为它需要更频繁地更新以保持其 Transform 最新。 此 UdonBehaviour 上有一个 SyncPickupColor 程序,在持有期间平滑更改颜色。它通过在 Update 事件中检查本地玩家是否是对象的所有者且 VRCPickup.get isHeld 为 true 来实现。注意它不使用 RequestSerialization,因为它设置为 Continuous——它会尽可能频繁地更新值。

每帧运行此检查,当条件为 true 时,程序会使用一些有趣的数学运算,在检查器中指定的两种颜色之间缓慢变化。

PickupSphere​

此对象实际上没有任何 Udon!它仅使用 VRC Pickup 和 VRC Object Sync 组件让用户以同步方式拾取和移动它。

PickupSphere

玩家检测​

响应玩家进入某个区域或与物理对象碰撞非常有用。这些示例程序说明了实现此目的的几种方法。

PlayerTrigger​

PlayerTrigger

这是检测玩家进入或离开区域的最常用方法。 "TriggerArea" 对象上有半透明蓝色材质、勾选 IsTrigger 的 Box Collider,以及带有 PlayerTrigger 程序源的 UdonBehaviour。

在此程序中,当任何玩家进入或离开碰撞器时,会触发 OnPlayerTriggerEnter 和 OnPlayerTriggerExit 事件。然后程序获取该玩家的 displayName 并更新目标画布上的文本。 PlayerTrigger Program

PlayerCollision​

此设置演示如何触发和响应 OnPlayerCollisionEnter/Exit 事件,当物理对象移入玩家的碰撞器时触发。 PlayerCollision

TriggerArea 对象有一个 FireOnTrigger Udon 程序,用于检测玩家进入其触发器区域,与上面的 PlayerTrigger 程序类似。在本例中,此事件用于向 Projectile 对象发送自定义事件 "Fire"。这将使 Projectile 立方体给自己添加一个力,使其向玩家移动。当它与玩家碰撞时,会将玩家的 displayName 写入目标文本字段。

请注意,此处的 PlayerCollision 事件仅会在经历这些事件的玩家本地触发。如果要通知其他玩家这些事件,您需要通过同步变量或自定义网络事件自行添加该功能。

PlayerParticleCollision​

PlayerParticleCollision Scene

此演示的设置与上面的 PlayerCollision 类似,使用触发器区域启动其他事件。在本例中,当玩家进入触发器区域时,SetActiveFromPlayerTrigger 程序将打开 CollisionParticles 对象。该对象带有一个 ParticleSystem,启用了世界碰撞和发送碰撞消息,向玩家发射粒子。附加到该对象的 Udon 程序 PlayerCollisionParticles 将触发图形中的 OnPlayerParticleCollision 事件,将受影响的玩家的 displayName 写入目标文本字段。

PlayerParticleCollision Program

Udon 同步播放器​

Udon Sync Player

此设置演示了使用 Unity/AVPro 视频播放器加载和同步视频播放的一种方法。这是一个大型程序,因此我们将其单独放在一个页面中。

CubeArraySync​

CubeArraySync

这个简单的程序创建了一个立方体网格,当有人点击时随机开关,同时使用极少的数据,展示了同步数组的强大功能。 CubeArraySync 程序有一个名为 data 的变量,是一个包含 25 个值的布尔数组。这意味着它有 25 个简单的是/否值,同步给每个用户。它还有一个名为 cubes 的 GameObject 数组,包含 25 个立方体。

当有人点击包含所有立方体的对象时,一个名为 "Randomize" 的自定义网络事件被发送到 CubeArraySync 对象的所有者。然后所有者使用 For 循环随机设置每个值为开或关,通过生成 0 到 1 之间的数字并检查该值是否大于 0.5。更新数组变量后,它调用 RequestSerialization,然后调用自定义事件 UpdateCubes。

Each user will turn on/off each cube based on the random value from Boolean array.

UpdateCubes 事件使用另一个 For 循环遍历数组中的每个是/否变量,并将其对应的立方体设置为开或关。此事件由所有者在更新数组后触发,或由 OnDeserialization 在 VRChat 为所有其他用户更新数组变量后触发。我们在此使用 OnDeserialization 而不是 OnVariableChange,因为数组变量目前不会触发变量更改事件,所以我们等待 OnDeserialization 中有新数据时更新场景。

对象池​

These cubes will never be this neat again once they start dropping and bouncing around.

对象池是一个帮助您管理对象集合的组件。它会自动同步其对象的活动状态。 此示例程序将盒子从天空一次一个地掉落到堆叠的网格中,当您点击盒子时,它会被移除并从天空重新生成。

为此,ObjectPool 程序运行一个简单的计时器,并尝试定期生成一个对象。池中的每个 Pooled Box 都有一个简单的 Pooled Box 程序,在 Start 时保存其初始位置,在启用时(由池生成时)恢复该位置,并在您点击时归还每个对象。

简单画笔系统​

即使是一个基本的画笔也需要相当多的工作,因此这个示例有自己的页面。