Search Unity

How to keep GameObjects in global data structures from not deleting across scenes?

Discussion in 'Scripting' started by Texashawk, Apr 26, 2015.

  1. Texashawk

    Texashawk

    Joined:
    Mar 19, 2013
    Posts:
    43
    Hello!

    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!
     
  2. Fajlworks

    Fajlworks

    Joined:
    Sep 8, 2014
    Posts:
    344
    I would recommend using the script on the link - http://wiki.unity3d.com/index.php/Singleton

    Code (CSharp):
    1. using UnityEngine;
    2. /// <summary>
    3. /// Be aware this will not prevent a non singleton constructor
    4. ///   such as `T myT = new T();`
    5. /// To prevent that, add `protected T () {}` to your singleton class.
    6. ///
    7. /// As a note, this is made as MonoBehaviour because we need Coroutines.
    8. /// </summary>
    9. public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    10. {
    11.     private static T _instance;
    12.     private static object _lock = new object();
    13.     public static T Instance
    14.     {
    15.         get
    16.         {
    17.             if (applicationIsQuitting) {
    18.                 Debug.LogWarning("[Singleton] Instance '"+ typeof(T) +
    19.                     "' already destroyed on application quit." +
    20.                     " Won't create again - returning null.");
    21.                 return null;
    22.             }
    23.             lock(_lock)
    24.             {
    25.                 if (_instance == null)
    26.                 {
    27.                     _instance = (T) FindObjectOfType(typeof(T));
    28.                     if ( FindObjectsOfType(typeof(T)).Length > 1 )
    29.                     {
    30.                         Debug.LogError("[Singleton] Something went really wrong " +
    31.                             " - there should never be more than 1 singleton!" +
    32.                             " Reopening the scene might fix it.");
    33.                         return _instance;
    34.                     }
    35.                     if (_instance == null)
    36.                     {
    37.                         GameObject singleton = new GameObject();
    38.                         _instance = singleton.AddComponent<T>();
    39.                         singleton.name = "(singleton) "+ typeof(T).ToString();
    40.                         DontDestroyOnLoad(singleton);
    41.                         Debug.Log("[Singleton] An instance of " + typeof(T) +
    42.                             " is needed in the scene, so '" + singleton +
    43.                             "' was created with DontDestroyOnLoad.");
    44.                     } else {
    45.                         Debug.Log("[Singleton] Using instance already created: " +
    46.                             _instance.gameObject.name);
    47.                     }
    48.                 }
    49.                 return _instance;
    50.             }
    51.         }
    52.     }
    53.     private static bool applicationIsQuitting = false;
    54.     /// <summary>
    55.     /// When Unity quits, it destroys objects in a random order.
    56.     /// In principle, a Singleton is only destroyed when application quits.
    57.     /// If any script calls Instance after it have been destroyed,
    58.     ///   it will create a buggy ghost object that will stay on the Editor scene
    59.     ///   even after stopping playing the Application. Really bad!
    60.     /// So, this was made to be sure we're not creating that buggy ghost object.
    61.     /// </summary>
    62.     public void OnDestroy () {
    63.         applicationIsQuitting = true;
    64.     }
    65. }
    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.
     
  3. Texashawk

    Texashawk

    Joined:
    Mar 19, 2013
    Posts:
    43
    Thank you Fajlworks. This is elegent and may serve other uses as well, as you say!

    -Steve
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    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.