The annoying thing about a lot of tutorials is that they put things like GameManagers into scenes and then start dragging references around all over the place.
Most of these things fail when they are marked DontDestroyOnLoad() and hold references all over the place to things that are NOT marked that way.
Broadly I call these constructs a “defective singleton.” I know what they’re trying to do but I am not sure I have even seen a single tutorial actually get it right.
And when I say “get it right” I mean a singleton construct that works in 100% of all use cases as well as in all future mis-use cases, such as when a user such as yourself slightly changes something, changes some order, tries to insert an extra “wave complete” scene, etc.
I actually have a hard-and-fast rule:
If it is going to be marked DontDestroyOnLoad(), then it NEVER gets placed in a scene.
To that end, I have two super-handy examples you can study and start from.
Simple Singleton (UnitySingleton):
Some super-simple Singleton examples to take and modify:
Simple Unity3D Singleton (no predefined data):
Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:
These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance
Alternately you could start one up with a RuntimeInitializeOnLoad
attribute.
The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.
If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:
public void DestroyThyself()
{
Destroy(gameObject);
Instance = null; // because destroy doesn't happen until end of frame
}
I engineered the above code to consider the standard Unity object lifecycle, which also might be interesting to you: