单例

场景里只有一个的 behaviour,任何地方都用 Type.Instance 取到。

更新于 2026-09-07

一个世界里总有些东西只有一份:比赛、商店、门的管理器。其他所有 behaviour 都要够得着它,而在 Inspector 里一个一个连引用,在数量到二十个之前都还行,直到出现一个谁也没记得去连的新预制体。

继承 Singleton<T>

using Udonite;

public class GameManager : Singleton<GameManager>
{
    public int score;

    public void Award()
    {
        score = score + 1;
    }
}

在一个 GameObject 上放一个,名字随你取,然后在任何别的 behaviour 里直接用:

GameManager.Instance.Award();

不需要属性,不需要自己写访问器,不需要拖引用,也完全不依赖物体叫什么名字。读 Instance 很轻,放在 Update 里也不必多想。

场景里只有一个,这件事在编辑时就会检查

如果场景里有两个,控制台会把两个物体都点出来,点击那条消息会选中其中之一:

Udonite: GameManager is a Singleton<GameManager> and there are 2 in the scene:
'Managers/GameManager', 'Spawn/GameManager'. A singleton is one behaviour, and
nothing can choose between these. Delete the extras.

如果一个都没有,也会告诉你,并且在你放上一个之前,场景里所有的 GameManager.Instance 都取不到东西。

这两种情况在每次 Udonite 编译时和每次保存场景时都会检查,所以就算你把第二个副本拖到了物体上,也会当场发现。

有好几个不同的单例是很平常的事。它们各自查找,绝不会把一个当成另一个交给你。

引用先就绪,值后到

GameManager.Instance 从第一帧起就能用。GameManager 在它自己的 Start 里赋的值则未必。

Unity 会在任何 Update 之前跑完所有 Start世界里不会,而且 Play 模式看不出这个差别,所以上传之前值得知道:

public override void Update()
{
    label.text = GameManager.Instance.score.ToString();   // 没问题
    title.text = GameManager.Instance.title;              // 第 1 帧可能还是空的
}

两种稳妥的做法。在 Inspector 里给它一个值,那是在 Start 之前就有的:

public string title = "Match";

或者等那个值本身,而不是等帧数:

public override void Update()
{
    if (ready)
        return;

    if (GameManager.Instance.title == "")
        return;

    ready = true;
    // 从这里开始就安全了
}

引用本身永远不需要等。

用静态字段存这个实例是行不通的

public static GameManager Instance;      // UDN0002

世界里每个 behaviour 都有自己的内存,所以 static 字段并不会在它们之间共享:两个 behaviour 会各拿一份自己的副本,谁也看不到对方写进去的东西。与其让世界悄悄地自相矛盾,Udonite 选择直接拒绝。

要"只有一个",用 Singleton<T>。至于永远不变的值,conststatic readonly 照样能用。

出了点问题 重新加载