参考

每一个绑定,什么会触发它,以及它不会做什么。

更新于 2026-09-08

所有内容都在 Udonite.Binding 中。

每个绑定的形状都一样:

成员 作用
Watch(control) 开始盯住;只触发事件
Bind(control, observable) 同上,并让一个 Observable 保持同步
Poll() 读取控件;在 Update 里调用
Unbind() 停止盯住,并放开 Observable
Value 不管有没有绑 Observable,控件当前的值

规则也一样:

  • 绑定的那一刻就写入控件,所以它一开始显示的是值,而不是设计师随手留下的内容。
  • 再次绑定会替换上一次,所以跑两遍的 Start 只会留下一个。
  • null 的控件或 Observable 会被忽略,而不是让 behaviour 停摆。
  • 已经加上的处理器会留着,无论你再 Watch 还是 Unbind。它们属于添加的人,而不属于控件;要丢掉就把事件字段清空。
  • 只有玩家的改动会触发事件。 通过给 Observable 赋值来移动控件不会。

被盯住的控件

这些需要在 UpdatePoll()

SliderBinding

成员
Action<float> OnChanged 玩家移动手柄时触发
Bind(Slider, Observable<float>) 双向
float Value 手柄在哪

ToggleBinding

成员
Action<bool> OnChanged 玩家点击时触发
Bind(Toggle, Observable<bool>) 双向
bool Value 是否勾选

InputBinding

成员
Action<string> OnChanged 每一次按键
Action<string> OnEndEdit 玩家改动后离开字段
Action OnFocused 玩家开始编辑
Bind(TMP_InputField, Observable<string>) 双向
string Value 字段里的内容

OnChanged 每按一个键就报告一次,因为绑在实时标签上的字段本该如此。如果你不要这个,就在按下按钮时读一次 Value

玩家正在打字时写入 Observable 会把光标弹到末尾。绑定自己不会这么做(轮询先把玩家的文字取进来,写回去的是同一个字符串),但在编辑过程中赋值的代码会。

被驱动的控件

没有事件,也不需要 Poll()。Observable 就是喂给它们的方式。

TextBinding<T>

成员
Bind(TextMeshProUGUI, Observable<T>) 显示这个值
Bind(TextMeshProUGUI, Observable<T>, prefix, suffix) 前后加字

例如 Bind(label, score, "Score: ", "")Bind(label, health, "", " HP")。null 值显示为空字符串,而不是出错。

ActiveBinding

成员
Bind(GameObject, Observable<bool>) 为 true 时显示
BindInverted(GameObject, Observable<bool>) 为 false 时显示

在同一个 Observable 上绑两个,就是一对配套的牌子。

被隐藏物体上的 behaviour 会停止运行。 隐藏绑定所在的物体会让它的 Update 停下,上面的 Poll() 也跟着停。把需要轮询的绑定放在一直显示的物体上。

FillBinding

成员
Bind(Image, Observable<float>) 已经在 0 到 1 之间的值
Bind(Image, Observable<float>, min, max) 你指定范围的值

范围是绑定的一部分,因为 fillAmount 是 0 到 1,而世界要数的东西几乎都不是。超出范围的会被夹住,空的或反过来的范围只会得到空的图,而不是除以零。

要让 fillAmount 起作用,Image 的 Type 必须设为 Filled

它不做什么,以及为什么

按钮。 点击是事件而不是值。Slider.valueToggle.isOnTMP_InputField.text 随时可读,"上一帧到现在有没有被点过"读不到,也就没有可轮询的东西。按钮仍然需要在 Inspector 里连到一个公开方法。

URL 输入框。 VRCUrlInputField 接受选中却从不获得焦点——直接调用 ActivateInputField()isFocused 仍为 false,这是实测的。VRChat 通过自己的键盘把文字送进去,所以在编辑器里根本无法验证。按 VRChat 的文档,在 Inspector 里用它的 OnEndEdit

成排的列表。ObservableList<T> 驱动一组行意味着创建和销毁物体,而在世界里这意味着 VRCObjectPool 和一堆关于所有权的决定。那是另一个包。

如果处理器抛出异常

在 Udon 里,一个异常会让 behaviour 在本次会话余下的时间里停摆,也没有办法只接住某一个再继续下一个。抛出异常的处理器会把剩下的通知、以及那个 behaviour 之后本该做的一切一并带走,所以处理器最好只做读值和更新这两件事。

出了点问题 重新加载