Search Unity

Missing Reference Exception Error.

Discussion in 'Scripting' started by unity_992A3F0D5222DB11167F, Jul 13, 2021.

  1. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Hi all,

    I am wondering if someone can shed some light on the error below. I am working on a 2D Metroidvania Style game and I am moving between 2 different scenes. I am using a do not destroy for the player prefab which is working fine but when I move back to the first scene and get hit by an enemy. I get the error below.

    I am very new to unity and coding in general and have got this far by completing a few courses online so please be patient with me as I am still learning.

    Please let me know if you need me to share any information that may help. Even if someone could point me in the right direction, that would be very helpful.

    Thank you.



    MissingReferenceException: The object of type 'PlayerController' has been destroyed but you are still trying to access it.
    Your script should either check if it is null or you should not destroy the object.

    LevelManager+<RespawnCo>d__7.MoveNext () (at Assets/Scripts/LevelManager.cs:37)

    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <24599fe2776145d58ab771516c063d56>:0)

    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)

    LevelManager:RespawnPlayer() (at Assets/Scripts/LevelManager.cs:32)

    PlayerHealthController : DealDamage() (at Assets/Scripts/Player/PlayerHealthController.cs:64)
    DamagePlayer:OnTriggerEnter2D(Collider2D) (at Assets/Scripts/Player/DamagePlayer.cs:13)
     
  2. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    The error tells you what's wrong, "The object of type 'PlayerController' has been destroyed but you are still trying to access it."
     
  3. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Hi RedRedPanda, Thank you so much for your reply.

    I am using the do not destroy on my player script so that I don't have multiple players when moving between scenes, so I think what is happening is that when I go into scene 2 from scene 1 and take the original player,

    once I come back to scene 1 and destroy the duplicate player. It is saying that it cannot find the player controller as it was destroyed.

    1) can I check if the following code looks correct to you?

    (I have attached this script to my player to stop duplicates)

    Code (CSharp):
    1. public class PlayerManager : MonoBehaviour
    2. {
    3.     public static PlayerManager instance;
    4.  
    5.  
    6.     private void Awake()
    7.     {
    8.         if (instance != null)
    9.         {
    10.             Destroy(this.gameObject);
    11.             return;
    12.         }
    13.      
    14.            instance = this;
    15.         //This keeps the player when loading into a scene
    16.         GameObject.DontDestroyOnLoad(this.gameObject);
    17.     }
    2) what would be the best way to move a player between scenes and ensure that all the scripts that are attached are still being read.

    Thank you again for taking the time to help.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,688
    For the singleton-ish construct above, this is always my go-to way:

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance!

    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:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    As for the actual error, I'll spare you the usual blurb I post about nullrefs since I think you understand that part. :)
     
  5. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Hi Kurt,

    thank you for the quick response and providing the links. I will give this a try with the hope of it working on my project.
     
  6. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Hi Kurt, thank you again for your reply.

    I tried both methods but sadly I could not get them to work in my game, it is possible due to my current level of coding so I will learn some more continue my search for an answer.

    The workaround at the moment, that has not crashed the game for me is to not use the 'do not destroy' function at all with the player script and then just have a player prefab ready in each scene. This seems to be okay for now but as I want the player to keep upgrades and such in the future, this apparently is not the best option. I am not sure if you or anyone else has an alternative on this.
     
  7. PizzaPie

    PizzaPie

    Joined:
    Oct 11, 2015
    Posts:
    106
    You probably have a direct reference to player object in the inspector in the first scene. Problem with DontDestroyOnLoad is such references are not "preserved" after reloading a scene*. Once you follow the singleton pattern you should never access that object from inspector references.


    *When loading such a scene first time the reference will work fine because there is only one Player, now when you reload it a second player object will get created and any scene objects referencing it through inspector will point to the new instance. But the new instance will run it s awake and get destroyed so all objects referencing it that way will stuck with a null ref or as Unity likes to call it missing ref.
     
    Last edited: Jul 14, 2021
  8. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Thank you PizzaPie for the explanation that really helps.

    I have read online that some people load a Gameobject just before the first scene (somewhere between the title screen and level 1/scene 1) and that game object will contain the player, the camera and maybe the UI so that these things will never actually exist in any scene to begin with and are just taken along through the whole game right from the beginning. Would you know how this is achieved or could you point me to some references?
     
  9. PizzaPie

    PizzaPie

    Joined:
    Oct 11, 2015
    Posts:
    106
    I am not aware of a way to create GameObjects without a scene, after all those are tightly connected so doubt it is doable.
    What you can do is create a scene with what you mentioned load it once at the start and then load/ unload additively the other scenes. Beware of additive loading it comes with its own caveats.
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,688
    Exactly this. There is always at least ONE scene, and even when there are two scenes, only one of them is the Active Scene, and this is where freshly-created GameObjects are placed.

    Additionally, when you mark a script as DontDestroyOnLoad, effectively it creates a special scene called DontDestroyOnLoad and puts those objects in there. That's all it is, which is why you can generally see the DDOL objects right in the scene.

    Because what you are doing spans scenes, get familiar with how that "lifetime" works: try make two or three little empty throwaway scenes and a few scripts , such as a GameManager singleton, and understand how lifecycles change. Personally I use bazillions of smaller scenes in my games, additively loaded on top of each other, like so:

    Additive scene loading is one possible solution:

    https://forum.unity.com/threads/right-way-for-performance-divide-scene.1023673/#post-6630961
    https://forum.unity.com/threads/right-way-for-performance-divide-scene.1023673/#post-6754330

    https://forum.unity.com/threads/problem-with-canvas-ui-prefabs.1039075/#post-6726169

    A multi-scene loader thingy:

    https://pastebin.com/Vecczt5Q

    My typical Scene Loader:

    https://gist.github.com/kurtdekker/862da3bc22ee13aff61a7606ece6fdd3

    Other notes on additive scene loading:

    https://forum.unity.com/threads/removing-duplicates-on-load-scene.956568/#post-6233406

    Timing of scene loading:

    https://forum.unity.com/threads/fun...ject-in-the-second-scene.993141/#post-6449718

    Also, if something exists only in one scene, DO NOT MAKE A PREFAB out of it. It's a waste of time and needlessly splits your work between two files, the prefab and the scene, leading to many possible errors and edge cases.

    Checking if everything is ready to go:

    https://forum.unity.com/threads/daily-events-and-content-changes.1108202/#post-7143713
     
  11. unity_992A3F0D5222DB11167F

    unity_992A3F0D5222DB11167F

    Joined:
    Jun 2, 2021
    Posts:
    10
    Thank you PizzaPie and Kurt, for the fantastic resources above I really appreciate the help here, I will try all the suggestions and see how I get on.
     
    Kurt-Dekker likes this.