Singletons
One behaviour per scene, reached from anywhere as Type.Instance.
A world usually has one of something: the match, the shop, the door controller. Every other behaviour needs to reach it, and wiring an inspector reference from each one works until there are twenty of them and a new prefab nobody remembered to wire.
Derive from Singleton<T>:
using Udonite;
public class GameManager : Singleton<GameManager>
{
public int score;
public void Award()
{
score = score + 1;
}
}
Put one on a GameObject, call it whatever you like, and reach it from any other behaviour:
GameManager.Instance.Award();
No attribute, no accessor to write, no reference to drag, and nothing that depends on what the object is named. Reading Instance is cheap enough to do in Update without thinking about it.
One per scene, checked while you edit
If the scene holds two, the console names both objects and clicking the message selects one of them:
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.
If it holds none, you get told that too, and every GameManager.Instance in the scene resolves to nothing until you add one.
Both are checked whenever Udonite compiles and whenever you save the scene, so dragging a second copy onto an object is caught straight away rather than in the world.
Several different singletons are ordinary. Each is found separately, so one can never hand you another.
The reference is ready before the values are
GameManager.Instance is available from the first frame. Anything GameManager assigns in its own Start might not be.
Unity runs every Start before any Update. A world does not, and Play mode does not show you the difference, so this is worth knowing before you upload:
public override void Update()
{
label.text = GameManager.Instance.score.ToString(); // fine
title.text = GameManager.Instance.title; // may be empty on frame 1
}
The reliable fixes are to give the field a value in the inspector, which is there before Start runs:
public string title = "Match";
or to wait for the value rather than for a frame:
public override void Update()
{
if (ready)
return;
if (GameManager.Instance.title == "")
return;
ready = true;
// safe from here
}
You never have to wait for the reference itself.
Holding the instance in a static field does not work
public static GameManager Instance; // UDN0002
Every behaviour in a world has its own memory, so a static field is not shared between them: two behaviours would each get their own copy and neither would ever see the other's writes. Udonite refuses it rather than letting a world quietly disagree with itself.
Singleton<T> is the supported way to have one of something, and const and static readonly are still fine for values that never change.