- Home /
Singleton that can react to game events
I would like to have a "manager"-type singleton object in my game that receives game events like FixedUpdate, Update, LateUpdate, etc. Of course, I can derive it from the MonoBehavior and stipulate that there should one instance of it in a scene (say, attached to the main camera), but this feels hacky and error-prone.
Is there an elegant way of doing this in Unity?
Answer by karlhulme · Oct 30, 2013 at 09:08 AM
Hi vadimcn,
To get the FixedUpdate/Update/LateUpdate game events I think we have no choice but to derive from MonoBehaviour. If so, the problem then becomes how to ensure that we only get one of them. The simplest solution I've found is to have the script check for multiple instances on load as follows:
public sealed class Manager: MonoBehaviour
{
public static Manager Instance { get; private set; }
void Awake()
{
if(Instance == null)
{
Instance = this;
}
else
{
throw new System.Exception("too many Manager's in use!");
}
}
void Update()
{
// check win conditions
}
void FixedUpdate()
{
// check win conditions
}
public void DoSomething(Vector3 v, string s, int n)
{
// change the win conditions
}
}
If you accidentally add this component to 2 GameObjects then you'll see errors. This is a clear sign to the designer that something has been setup wrong and hence is easy to fix.
This instancy-singleton can then still be accessed by other code, as follows...
Manager.Instance.DoSomething(Vector3.up, "hello", 3);
p.s. I think Unity is single-threaded, otherwise you might need a lock statement around Awake to be sure of not getting a second instance.
I was hoping there'd some way to check this at design time, but, oh well... Runtime checks will have to do.
Thanks!
Answer by rutter · Nov 05, 2013 at 12:04 AM
I tend to use a singleton pattern something like this:
private Manager _instance;
public Manager instance {
get {
if (_instance == null) {
_instance = new GameObject("Manager").AddComponent<Manager>();
Object.DontDestroyOnLoad(_instance);
}
return _instance;
}
}
The first time anything accesses instance
, a Manager will be spawned. All other times, the existing Manager will be used.
Other scripts can then call instance methods:
Manager.instance.DoSomething();
Depending on your particular needs, it may be advantageous to spawn a prefab instead of just attaching the component.
If you'd rather encapsulate the instance, you can write static methods which access it internally.
You could also use a static constructor, but I've found that can cause errors when interacting with Unity (ie: calls to load resources or attach components tend to fail when called outside of the main thread).