Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

DontDestroyOnLoad question

Discussion in 'Editor & General Support' started by Tamaz23, Feb 19, 2020.

  1. Tamaz23

    Tamaz23

    Joined:
    Feb 19, 2020
    Posts:
    3
    I have an empty gameObject that I made just so that I could house a certain script. When my character dies, the scene reloads, so I put a DontDestroyOnLoad function on that gameObject so that the script would stay, since I need it to stay when the character dies. Only problem is, when the character dies, all of the references that I manually dragged the script into disappear and say “missing”, so the script only works for one death and then that’s it. I think it’s because when the character dies and the DontDestroyOnLoad function is called, the gameObject is no longer in the scene (from my understanding of the function), and so all of the references of the script inside the gameObject are gone. Any solutions?
     
  2. unit_dev123

    unit_dev123

    Joined:
    Feb 10, 2020
    Posts:
    989
    correct, instead if move logic script away from character or simply set character to invisible instead destroy object.
     
  3. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,135
    It's not the act of calling DontDestroyOnLoad that causes the references to go missing, it's SceneManager.LoadScene which unloads the active scene and destroys all scene objects in it before loading the scene anew. All reference that point from the persistent object to objects in the reloaded scene will be lost for this reason.

    One way to fix this would be to manually reconnect all references whenever the scene reloads by using the SceneManager.activeSceneChanged callback.
    Code (CSharp):
    1. private void Awake()
    2. {
    3.     DontDestroyOnLoad(gameObject);
    4.     SceneManager.activeSceneChanged += OnActiveSceneChanged;
    5. }
    6.  
    7. private void OnActiveSceneChanged(Scene unloadedScene, Scene loadedScene)
    8. {
    9.     // refetch all references here
    10. }
    11.  
    12. private void OnDestroy()
    13. {
    14.     SceneManager.activeSceneChanged -= OnActiveSceneChanged;
    15. }
    A possible issue with this method is that the Awake, OnEnable and Start event functions of all scene objects occur before the activeSceneChanged callback, so there is a possibility of NullReferenceExceptions occurring if some scene objects reference the persistent object. It is possible to get around this by loading the scene async with allowSceneActivation set to false and fetching all the references from the scene before actually setting it active - but this quite a bit more complex to pull off.


    You could also avoid using DontDestroyOnLoad altogether, and instead use other methods to allow some state of your object (but not the Object reference data) to persist through scene transitions.

    For example serialize some field values during OnDestroy and restore them during Awake.

    Static variables or ScriptableObject assets could all be used to make some data persist through scene reloading.
     
  4. Tamaz23

    Tamaz23

    Joined:
    Feb 19, 2020
    Posts:
    3
    How exactly would I get all of the references within the OnActiveSceneChanged function?
     
  5. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,135
    It depends.

    If only one instance of a component type exists in the scene you can simply use Object.FindObjectOfType.

    If there might be multiple instances you'd first need to locate the correct GameObject using something like GameObject.FindWithTag.

    If it is not possible to programmatically figure out the right GameObject then using SceneManager.activeSceneChanged is probably not be a good solution here. Then it would probably be best to avoid using DontDestroyOnLoad at all, so you don't lose the Object references in the first place.