你的第一个世界
一个任何人都能按的按钮和一个所有玩家都看到相同数字的计数器,从空项目到上传完成,大约十五分钟。
你将做一个计数器:一个任何人都能按的方块,一个显示它被按了多少次的标签,并且每个玩家屏幕上的数字都相同,包括一小时后才进来的玩家。它会用到编译器、网络包和一个普通的 UI 标签,这已经是一个真实世界所做事情的大部分,只需要大约二十行 C#。
1. 安装
- 在 VRChat Creator Companion 中打开 Settings → Packages → Add Repository,粘贴
https://udonite.github.io/vpm/index.json,点击 Add。 - 创建或打开一个世界项目。需要 Unity 2022.3 和 Worlds SDK 3.10 或更新版本。
- 在项目的包列表中添加 Udonite 和 Udonite Net。
从这里开始,Udonite 会自动把你的 C# 编译成 Udon;Net 包提供计数器需要的同步值。
2. 搭建场景
- GameObject → 3D Object → Cube,命名为
Counter,放在玩家能碰到的位置。方块上的碰撞体就是它能被按的原因。 - GameObject → UI → Canvas,把 Render Mode 设为 World Space,缩小到可读的尺寸(缩放
0.005是个合理的起点),放在方块上方。 - 在画布内 UI → Legacy → Text,命名为
Label,文本填0。这里用旧版组件就够了,不需要导入任何东西。
3. 编写行为脚本
创建 Assets/Counter.cs:
using Udonite;
using Udonite.Net;
using UnityEngine;
using UnityEngine.UI;
public class Counter : UdoniteBehaviour
{
public Text label;
private Synced<int> count = new Synced<int>();
public override void Start()
{
InteractionText = "Press";
count.Subscribe(OnCountChanged);
label.text = count.Value.ToString();
}
public override void Interact()
{
Ownership.Claim(gameObject);
count.Value = count.Value + 1;
}
private void OnCountChanged(int value)
{
label.text = value.ToString();
}
}
撑起整个世界的是三件事:
Interact在玩家按下物体时运行。它是UdoniteBehaviour的普通成员,所以名字拼错会是编译错误,而不是悄无声息地什么都不发生。Synced<int>是每个客户端都持有的计数。写入.Value会保存它并请求 VRChat 复制;后来加入的玩家无需任何人重发就能收到当前值。只有物体的所有者可以写入,这就是Ownership.Claim的用处:谁按下就成为所有者,然后写入。Subscribe在值到达时于每个客户端运行处理程序,包括写入它的那个客户端,因此标签只在一个地方更新。Start里那行label.text覆盖第一次变化之前的时刻。
这里没有任何 Udon 专有语法。没有需要与同步模式配对的 sync 属性,没有需要记得调用的序列化方法,也没有需要避开的关键字清单。
4. 挂载并编译
- 把
Counter.cs拖到Counter方块上。 - 把
Label物体拖进检视面板的 Label 字段。 - 保存场景。
保存即编译。Udonite 会在 C# 组件旁挂上一个 Udon 程序;编译成功什么都不打印,Udon 无法运行的内容会在控制台被逐项点名,附带 UDN 代码和改写建议。Udonite → Open Window → Compile 会手动编译所有内容并打印一行摘要,在刚把脚本拖到物体上之后很有用。
5. 试一试
按下 Play。ClientSim 给你一个本地玩家;走到方块前按下它。标签会往上数,而 Udon 程序运行时 C# 组件是禁用的,所以你测试的就是将要发布的东西。
ClientSim 不运行序列化,因此在编辑器里计数是本地的。要看它穿过网络,在 SDK 控制面板用 Build & Test 开两个客户端:在一个里按下,另一个的标签会跟上。
6. 上传
像任何世界一样,从 VRChat SDK 控制面板构建并上传。发布出去的是 Udonite 挂载的 Udon 程序,C# 留在你的项目里等待下一次编辑。
接下来
- 让计数在所有人离开又回来后仍然保留:Persistence。
- 计数超过一百时通知一个 Discord 频道:Net 包的消息,以及控制台里的托管中继。
- 看看什么能编译:语言支持是那份清单,比你预想的长。
- 当某些东西被拒绝时:诊断解释每一个代码。