So here’s what I’m trying to do: I have a scene dedicated to creating stars for a galaxy map with different characteristics (size, type, luminousity, etc). and they each have a specific prefab depending on the type of star. What I’m running into is even though I have a global galaxy object list variable (gList) attached to a global GameEngine object, when the scene changes the objects in the list are destroyed and the draw star routine won’t work.
When I try to move the star creation routine into the same scene as the display map scene, I get duplicates (I use a temp GameObject to assign the star variables, then add that temp GameObject to the global gList). When I use ‘DontDestroyOnLoad’ I still get duplicates (it keeps the temp GameObject star through to the next scene.) I’m still getting used to thinking ‘the Unity way’ and in a traditional OOP program this would work fine.
In short: What can/should I do to keep a global GameObject list protected from automatic mass deletion that I can access and manipulate throughout several scenes of a game, or is this even possible? This is key to my game (a turn-based game) Thanks!
using UnityEngine;
/// <summary>
/// Be aware this will not prevent a non singleton constructor
/// such as `T myT = new T();`
/// To prevent that, add `protected T () {}` to your singleton class.
///
/// As a note, this is made as MonoBehaviour because we need Coroutines.
/// </summary>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
private static object _lock = new object();
public static T Instance
{
get
{
if (applicationIsQuitting) {
Debug.LogWarning("[Singleton] Instance '"+ typeof(T) +
"' already destroyed on application quit." +
" Won't create again - returning null.");
return null;
}
lock(_lock)
{
if (_instance == null)
{
_instance = (T) FindObjectOfType(typeof(T));
if ( FindObjectsOfType(typeof(T)).Length > 1 )
{
Debug.LogError("[Singleton] Something went really wrong " +
" - there should never be more than 1 singleton!" +
" Reopening the scene might fix it.");
return _instance;
}
if (_instance == null)
{
GameObject singleton = new GameObject();
_instance = singleton.AddComponent<T>();
singleton.name = "(singleton) "+ typeof(T).ToString();
DontDestroyOnLoad(singleton);
Debug.Log("[Singleton] An instance of " + typeof(T) +
" is needed in the scene, so '" + singleton +
"' was created with DontDestroyOnLoad.");
} else {
Debug.Log("[Singleton] Using instance already created: " +
_instance.gameObject.name);
}
}
return _instance;
}
}
}
private static bool applicationIsQuitting = false;
/// <summary>
/// When Unity quits, it destroys objects in a random order.
/// In principle, a Singleton is only destroyed when application quits.
/// If any script calls Instance after it have been destroyed,
/// it will create a buggy ghost object that will stay on the Editor scene
/// even after stopping playing the Application. Really bad!
/// So, this was made to be sure we're not creating that buggy ghost object.
/// </summary>
public void OnDestroy () {
applicationIsQuitting = true;
}
}
I think it really does a great job of keeping a single instance and avoiding duplicates when reloading or switching scenes. You can always use this as a starting point to achieve a persistent list manager.
DontDestroyOnLoad prevents a single GameObject from being destroyed. It does not prevent other objects it’s pointing at from being destroyed (IE. it doesn’t work like a GC).
So, if you want your spawned galaxy prefabs to not get destroyed, you’ll have to call DontDestroyOnLoad on their container objects.
Although, unless the galaxy data needs to be receiving Update, Start, Collision or any other MonoBehaviour calls, you could just leave them as normal (not deriving from MonoBehaviour) objects, in which case they won’t be destroyed by a scene load. If you need to store data about the galaxies, consider making them ScriptableObjects, which is the class you derive from when you need to store objects that are not going to be interacting with the scene.