Search Unity

The object of type X has been destroyed but you are still trying to access it.

Discussion in 'Scripting' started by Antviss, Feb 5, 2017.

  1. Antviss

    Antviss

    Joined:
    Jan 8, 2017
    Posts:
    12
    Hello everyone,

    I'm in quite a pickle here as can't find any answers to match my situation.

    In my game (UI based) i have 3 scenes:

    SCENE 1:

    Is just generic loading page which connects to the backend and moves to next scene when connection has been established.

    SCENE 2:

    Is a login page. When the connection to the backend is established, an event is triggered which checks if the user is currently logged in by checking the presence of an AES encrypted file and if it exists it decrypts it and passes the login details or auth token to an authentication method which authenticates the user to the backend.

    If user is already logged in (encrypted file exists) they won't even see SCENE 2...unless the credentials have changed in the meantime, of course. The above happens quickly and when complete it loads SCENE 3.

    If the user is not logged in (encrypted file doesn't exist), then they are prompted for username and password and the LOGIN button creates the file, authenticates the user to the backend and loads SCENE 3.

    SCENE 3:

    This, as you suspected is the main scene. Stuff happens here with events sent to the backend, handling of responses, UI changes and the works. Normal stuff...

    Now...here's the catch. There's a LOGOUT button in this scene which when pressed it does the following (in this order):

    - Deletes the encrypted file holding the current credentials
    - Resets the connection to the backend
    - Goes back to SCENE 2
    (nothing else)

    This works as intended. The user then logs in and SCENE 3 is loaded with the current user's stats pulled from the backend. But when I interact with any object in the scene I get the below error.


    If I close the application and reopen it it goes through the normal process as above and everything works ok. So it's got to be because I went from SCENE 3 to SCENE 2...then back to SCENE 3.

    I can't figure out what to do to discard SCENE 3 when player logs out and then reload a fresh SCENE 3 when they log in (in the same session).

    There are no DoNotDestroyOnLoad objects in scene 3.

    I hope the above makes sense.

    Many thanks for your time and assistance.

    Alex
     
    chandana1 and grot0130 like this.
  2. Antviss

    Antviss

    Joined:
    Jan 8, 2017
    Posts:
    12
    The error is:

    MissingReferenceException: The object of type X 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.


    Where X is the object name that was affected by the action. So it's not just TEXT. It depends on what the first interraction with the scene is and what script gets called.
     
  3. Antviss

    Antviss

    Joined:
    Jan 8, 2017
    Posts:
    12
    UPDATE:

    I'm getting a bit closer to fixing this. I have added the below wrapper:

    Code (CSharp):
    1. if(this!=null)
    2. {
    3.  
    4. // function body
    5.  
    6. }
    to 6 functions in 6 scripts which are referenced in SCENE 3. And now it works as intended. But it doesn't seem very efficient. Especially since the scene will grow a lot still as I'm just at the beginning of developing this game. Is there another way of solving this?

    Worth noting: All the functions that I added the above wrapper to are functions that are called by an event (not the same event, mind you) i.e:

    Code (CSharp):
    1. void Start () {
    2.         GameManager.OnPopUp += PopUp;
    3.       }
    4.  
    5.     public void PopUp()
    6.     {
    7.         if (this != null)
    8.         {
    9.             anim = GetComponent<Animator>();
    10.             anim.enabled = true;
    11.             anim.SetTrigger("Slideup");
    12.         }
    13.     }
    So maybe this means something to a more seasoned developer?
     
    himanshu817 and arbix_studio like this.
  4. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    Hello.
    I think that the OP has solved his issue, but I will share my solution for future reference.
    I faced the same problem and found out that the culprit is the event.
    When you first add a listener to an event that is in a static class of your own, which is what I've done and what the OP was probably doing in this line :
    1. void Start () {
    2. GameManager.OnPopUp += PopUp;
    3. }
    The listener that is added will stay there even if the game-object holding the script is destroyed.
    So when you change the scene, that script with the event listener will be destroyed but the listener will stay, and when you open the scene again, (regardless of adding a new listener) then call the event from somewhere, that old listener will be called but it's script (and object)will be missing, thus throwing that exception.
    The solution is at Awake or Start, to either remove all listeners of your event, or check if any of them has the same name as the one you're going to add.
    One way to do that would be :

    Code (CSharp):
    1.  
    2.  public delegate void EventType();
    3.  public static event EventType EventInstanceName;
    4. public static void RemoveEventListener(Action methodListener)
    5.     {
    6.         foreach (Delegate d in EventInstanceName.GetInvocationList())
    7.             if (d.Method.Name == method.Method.Name)
    8.                 EventInstanceName-= (EventType)d;
    9.     }
    This should be in the class managing the event.
     
  5. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    I think I'm hitting the same issue, but I'm new to this and dont understand the fix above, or where to even put it.
    I have a scene2 scene which is working fine standalone.
    It has a level generator in it which creates a load of pieces.

    I've now added a mainmenu scene before it. Which works fine once, but if I then go back to main menu and back to scene2, it falls over with:

    MissingReferenceException: The object of type 'LevelPiece' 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.
    UnityEngine.Component.GetComponent[SpriteRenderer] () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/ComponentBindings.gen.cs:48)
    LevelGenerator.UpdateSprites () (at Assets/scripts/LevelGenerator.cs:485)
    LevelGenerator.Start () (at Assets/scripts/LevelGenerator.cs:35)

    This first seems to fail at the part of my level generator where I've already created by pieces, and am now going through them one my one updating the sprite paths.

    SpriteRenderer[] renderer;
    Sprite RunwayOut;
    Sprite CommsTower;
    Sprite ControlTower;
    renderer = new SpriteRenderer[pieces.Count];
    for (int x=0;x<pieces.Count;x++){
    renderer[x] = pieces[x].GetComponent<SpriteRenderer>();

    Looks like it fails in other places afterwards.

    Finally, as I say this was all developed in scene2, with all the functionality in one scene initially. Now that I have added a main menu, should I be moving all of my level generation stuff into the main menu, and referencing it from scene2?
    The mainmenu already has DontDestroyOnLoad (transform.gameObject); so I can read variables from it.
    Or should it stay in scene2 and be regenerated each time?

    Thanks in advance.
     
  6. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Not sure if it helps, but my LevelGenerator script is a singleton.
    And looks like :

    void Awake(){
    instance = this;
    }

    // Use this for initialization
    void Start () {
    GenerateInitialPieces ();
    GenerateTextPieces ();
    PrintValues ();
    //Debug.Log ("Calling Sprite Update");
    UpdateSprites ();

    }
    When I run from the menu for the first time, all is OK, and I can see all of my LevelPieces that have been generated in the hierarchy.
    When I exit back to the menu, by entire scene2 disssapears from the hierarchy.
    When I go back into scene2 from the main menu, I once again see all of the levelpieces that have been generated on my canvas.
    So they are being recreated.
    However, I have noticed that they begin at sequence/index 34.
    It uses pieces.Count to get this when creating the objects in the list, so it does look like I need to somehow destroy the old list first.

    From what I can see I'm creating a new one in the LevelGenerator script.
    public class LevelGenerator : MonoBehaviour {
    public static LevelGenerator instance;
    public Transform levelStartPoint;
    public static List<LevelPiece> pieces = new List<LevelPiece> ();
    public static List<TextPiece> textPieces = new List<TextPiece> ();
    public LevelPiece LevelPiece;
    public TextPiece TextPiece;
    private StandardVars standardVars = new StandardVars();
    private int lastPiece;
     
  7. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    Please use code tags, as described in the first (pinned) post in every forum here. Posting code without using the code tags properly makes it nigh-unreadable, and most people here won't even bother trying to decipher it.

    The general idea (in response to the OP) is that any object that handles adding a delegate to an event needs to handle removing that delegate when it's destroyed. It's that simple. There's the built-in OnDestroy method that makes this process easier if needed.

    As to your specific issue newcoder, there aren't any events or delegates that I see in the code you've posted (I think), so either the problem is occurring elsewhere or your issue is unrelated to the OP's issue, aside from you both trying to access a destroyed object. In your case, my guess is that you have a singleton with DontDestroyOnLoad, you're filling it with references to LevelPieces as you create them, but you aren't clearing the list when the scene is changed so it's still trying to access old pieces when you go to make the new ones.

    Toss pieces.Clear() / textPieces.Clear() at the top of the GenerateInitialPieces or GenerateTextPieces or whatever and you should be fine. If your singleton is on a DontDestroyOnLoad object, keep in mind that Awake and Start only get called once when the object is first created, not once per scene load, and if you're not using DontDestroyOnLoad but recreating the singleton when the scene is loaded, then consider not using static objects, because they're (pointlessly) keeping their values across scene loads.
     
    unity_sx4JP-iZmsMziw likes this.
  8. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Thank you for your detailed reply. And apologies for the code tags.
    That does sound likely be the cause.
    I've just checked and it is a singleton:
    Code (csharp):
    1.  
    2. public class LevelGenerator : MonoBehaviour {
    3.    public static LevelGenerator instance;
    4.    public Transform levelStartPoint;
    5.    public static List<LevelPiece> pieces = new List<LevelPiece> ();
    6.    public LevelPiece LevelPiece;
    7.    void Awake(){
    8.        instance = this;
    9.    }
    10.  
    11.  
    12.  
    I've made no attempt to clear the list. I'd just assumed it all got destroyed and started again when the scene was terminated - and a new scene was same as starting from the beginning.


    In fact, one of the first things I was going to try when I got home was to add something to the onDestroy method to remove all pieces one by one and see if that helped, but I will try your suggestion first.

    edit: Actually, I'm pretty certain I DO NOT have DoNoDestroyOnLoad set on the levelgenerator script. The only place I put this was on a UImanager script on the Main Menu scene, and that was only so I could reference variables from it within my scene2 (which is were the level generator is). Does this still sound like the issue? I'll try it anyway.

    edit2:
    The error I'm getting is actually from the levelGenerator script. I note you suggest that a singleton elsewhere may be trying to reference them, but it is actually itself.

    To explain, my code generates (lets say 18) objects.
    It then goes through each one in a loop checking a flag and amending the sprite path.
    On first run these objects are numbered 0-17 internally

    But on the 2nd run they are labelled internally 18-35.
    And the first place I get the error is the loop that goes from 0 to <pieces.Count

    I think the answer you posted may still be the correct answer, but I'm not sure my scenario matches what you are suggesting exactly. I wont be able to try it for a good few hours unfortunately.

    Thanks again.
     
    Last edited: Jan 12, 2018
  9. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Firstly, thanks and well done. Adding pieces.Clear() fixed my immediate issue.
    Unfortunately I had others after that.

    I spent a couple of hours watching and reading on Singletons. And I realised that I only really had 1, and I wasn't even using that properly. So I was doing loads of finds etc.

    I've set about trying to add more in so I can share variables more easily. I dont know whether I'm doing the right thing or not, but I've now got a couple of issues that I really dont understand.

    The main one is that my main aeroplane sprite object, that the camera is based on, seems to die immediately.
    As soon as I go into the 2nd scene, I've put watches on it and I can see it going into the Dont destroy and aeroplane = this;

    Code (csharp):
    1.  
    2. public class Aeroplane : MonoBehaviour {
    3.     public float speed = 0.1f;
    4.    
    5.     public LevelGenerator levelgenerator;
    6.  
    7.     public static Aeroplane aeroplane;
    8.  
    9.     void Awake() {
    10.         if (aeroplane == null) {
    11.             DontDestroyOnLoad (gameObject);
    12.             aeroplane = this;
    13.         } else {
    14.             if (aeroplane != this) {
    15.                 //Destroy (gameObject);
    16.             }
    17.         }
    18.     }
    19.  
    and fails imediately with:
    Code (csharp):
    1.  
    2. MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
    3. Your script should either check if it is null or you should not destroy the object.
    4. CameraController.LateUpdate () (at Assets/scripts/CameraController.cs:19)
    5.  
    The CameraController script is attached to my main camera.
    Code (csharp):
    1.  
    2. MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
    3. Your script should either check if it is null or you should not destroy the object.
    4. CameraController.LateUpdate () (at Assets/scripts/CameraController.cs:19)
    5.  
    It is literally just :
    Code (csharp):
    1.  
    2. public class CameraController : MonoBehaviour {
    3.  
    4.     public GameObject aeroplane;
    5.     private Vector3 offset;
    6.     private Vector3 screenSizeOffset = new Vector3 (23f,0f,0f);
    7.  
    8.  
    9.     // Use this for initialization
    10.     void Start () {
    11.         offset = transform.position - aeroplane.transform.position;
    12.     }
    13.    
    14.     // Update is called once per frame
    15.     void LateUpdate () {
    16.         transform.position = aeroplane.transform.position + offset + screenSizeOffset;
    17.     }
    18. }
    19.  
    and I have dropped the Aeroplane object onto the static variable in Unity inspector.

    What am I missing? Is there some silly syntax error, or am I trying to do something wrong.

    For reference, this all worked perfectly 2 days ago as a single scene. It has fallen apart because of 2 things:
    1. I added a main menu scene before it.
    2. Off the back of our earlier discussions I've tried to add in more singletons, as I was doing loads of finds to make things work.

    Apologies, I realise this thread has gone off on a bit of a tangent, but I'm getting myself really confused now.
    Thanks again.
     
  10. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    My favourite approach to using singletons is to make all of the public methods static on a singleton, that way you can access them by using SingletonName.Method() from anywhere in the program. The singleton just needs to reference its own instance to get access to any inspector-displayed fields in those functions (using the "aeroplane" static reference internally). In your example, I would make a public static method called "GetTransform()" which returns the Transform of the object instance with "return aeroplane.GetComponent<Transform();" or whatever.
    Code (CSharp):
    1. public class Aeroplane : MonoBehaviour
    2. {
    3.     [SerializeField]
    4.     protected float speed = 0.1f;
    5.  
    6.     [SerializeField]
    7.     protected LevelGenerator levelgenerator;
    8.  
    9.     protected static Aeroplane instance = null;
    10.  
    11.     protected void Awake()
    12.     {
    13.         if (instance == null)
    14.         {
    15.             DontDestroyOnLoad (gameObject);
    16.             instance = this;
    17.         }
    18.         else
    19.         {
    20.             if (instance != this)
    21.                 Destroy(gameObject);
    22.         }
    23.     }
    24.  
    25.     public static Transform GetTransform()
    26.     {
    27.         return instance.GetComponent<Transform>();
    28.     }
    29. }

    In your case, you made the reference to the instance public instead (that's fine, just a style choice), so the CameraController doesn't need a public reference to an Aeroplane object type, it only needs to call Aeroplane.aeroplane.transform to get its Transform through the static interface.

    Drag-and-dropping a reference from an object marked DontDestroyOnLoad will cause problems- this is because the specific instance of that GameObject that you're dragging and dropping is not necessary the same instance that will exist when that scene is loaded. The specific instance of that singleton may be destroying itself, because another copy of the singleton already exists in the scene ("there can be only one")- this is precisely why you must use the static interface to get the instance, and not the inspector.

    I hope all of that makes sense- let me know if you have any additional questions or concerns, or if you need clarification about something.
     
    Last edited: Jan 12, 2018
  11. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    class fields do have initial default values in C#?
     
    DonLoquacious likes this.
  12. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    I actually deleted it before you commented- I made the transition to C# around the same time I started using Unity and it really bugs me seeing uninitialized variables. I felt like I might be wrong so I went and checked, then deleted that part from the answer. *shrugs*
     
  13. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Ah, cool, no worries. I was just adding that :) Didn't see your update before, sorry.
     
  14. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Thanks again for the detailed reply. That does make some sense.
    Although it is still failing with the same message at the same point.

    I did start using functions as you suggested, but there were quite a lot, and you suggest it should still work if I just access the variables publically? I think that would be my preference, but equally I'm happy to go with what you say if it gets this working. The problem initially is there would be too many functions to add in at once to even be able to test my immediate problem.

    I've gone through and taken out the public declarations for aeroplane in any script, and replaced with
    Aeroplane.instance.transform.position in the code. It all compiles.

    As I understand it, although have suggested you prefer using functions, I should still be able to access the private variables, which appears to be the case. I've checked the Unity inspector and all references to aeroplane are removed there.

    I'm still using :
    Code (csharp):
    1.  
    2. public static Aeroplane instance;
    3.  
    in the declaration of the aeroplane class so I can access these variables?

    So unless I've misunderstood something I must have something lying around? Unless you have any other suggestions or observations.

    For whatever reason the Aeroplane object does seem to dissapear in the Unity hierarchy when I run, indicating it is being closed down.

    Is this the only place that can be happening, and if so is there anything wrong with it?
    Code (csharp):
    1.  
    2. public static Aeroplane instance;
    3.  
    4.     void Awake() {
    5.         if (instance == null) {
    6.             DontDestroyOnLoad (gameObject);
    7.             instance = this;
    8.         } else {
    9.             if (instance != this) {
    10.                 Destroy (gameObject);
    11.             }
    12.         }
    13.     }
    14.  
    15.  
    I think what I will do is drop back to a backup from a couple of days before I put the main menu screen on it, I'll then try to get the singleton classes implemented on the approriate objects at that stage rather than trying to implement them in whilst other things are a bit flaky. Hopefully I'll have better luck that way.

    Thanks again.
     
  15. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    One more thing while I remember to ask.
    If aeroplane is my 'player' object, even before it was singleton, I don't really understand how it could get more than one instance?

    It is attached to an aeroplane gameobject in unity, but that's it.

    I am starting to think this may be a red herring, and the answer lies elsewhere.

    As far as I can tell I have removed every public aeroplane ever created in the scripts.

    Thanks, I really appreciate the time you've spent already on this.
     
  16. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Apologies for carpet bombing the thread....
    I've gone though and converted a load more stuff.
    The airplane sprite actually now looks like it is working, although the camera isn't following it (will look at that later).
    When I'm debugging I have put watches on a panel of buttons which is dissapearing.

    It is defined as
    Code (csharp):
    1.  
    2. public class InteractionPanel : MonoBehaviour {
    3.     public bool panelOn;
    4.     public bool startInteraction;
    5.     public  int interactionNumber;
    6.     //public InteractionPanel panel;
    7.     //public Aeroplane aeroplane;
    8.     public static InteractionPanel instance;
    9.  
    10.     void Awake() {
    11.         if (instance == null) {
    12.             DontDestroyOnLoad (gameObject);
    13.             instance = this;
    14.         } else {
    15.             if (instance != this) {
    16.                 Destroy (gameObject);
    17.             }
    18.         }
    19.     }
    20.  
    21.  
    This is all set up in the unity hierarchy and is visible when I start the game. I've put watches on in the debugger and it goes into:
    13 instance = this - still there
    13 then into instance = this again - still there
    16 then into Destroy (gameObject) - dissapears after this step

    So it does look like something is trying to set this up twice.
    After it dissapears it is no longer in the Unity hierarchy.

    But I've been through all of my scripts and the hierarchy. I cannt see anything either having it assigned to a public variable in inspector, decalring a new object of type InteractionPanel, or accessing anything other than InteractionPanel.instance.blah

    I cant work out if I'm missing one somewhere, or if I am missing something more obvious.
     
  17. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Just bear in mind that static survives reloading a scene and it's references usually do not, so it will point at something that is garbage after loading. You should set up instances anyway regardless if they're null or not in Awake if they will be static.
     
  18. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Sorry hippocoder, that doesn't mean much to me unfortunately.
    I'm on beginner-2 level at present :(

    Incidentally, I got round the issue on my previous post by commenting the destroy line (16) , though that obviously isn't ideal and I dont understand why that would be required.

    In case you saw my now recently deleted part of this thread re sprites, that is now resolved. My sprite prefab had been made invisible in unity so all subsequent ones were invisble.

    All of the above was with my main menu disabled. Now I need to see if that all breaks things again.

    And sure enough, it does. Going into game from main menu works, but as soon as I exit the game back to main menu it bombs. :(

    Code (csharp):
    1.  
    2. MissingReferenceException: The object of type 'LevelPiece' has been destroyed but you are still trying to access it.
    3.  
    Do I need to destroy everything cleanly when I exit? This is all I'm doing now.

    Code (csharp):
    1.  
    2.     public void ExitButtonOnCLick() {
    3.         Debug.Log ("Clicked Exit");
    4.         //GameObject levelGenerator = GameObject.Find("LevelGenerator");
    5.  
    6.         //levelGenerator.DestroyAll();
    7.         //Application.UnloadLevel(1);
    8.         Application.Quit();
    9.         Application.LoadLevel(0);
    10.     }
    11.  
    12.  
    Your script should either check if it is null or you should not destroy the object.
    Code (csharp):
    1.  
    2. UnityEngine.Component.GetComponent[SpriteRenderer] () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/ComponentBindings.gen.cs:48)
    3. LevelGenerator.UpdateSprites () (at Assets/scripts/LevelGenerator.cs:511)
    4. LevelGenerator.Update () (at Assets/scripts/LevelGenerator.cs:548)
    5.  
    It looks like it dies as it goes back to the mainMenu scene, so presumably the level pieces get destroyed in the background but there is something still trying to render them.
    Still, at least I have what I had before the main menu set up as Singleton and referencing directly rather than the previous finds I was doing everywhere.

    I have to go out now, but will take a look at this when I get back, hopefully something simple.
    Once again, thanks for your help and patience, very much appreciated.
     
    Last edited: Jan 13, 2018
  19. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I don't think you should run the line 'Application.Quit' to go back to the main menu :) try commenting that out & re-running your game.
     
  20. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    I think I put that in when I was experimenting yesterday. Taken out but just the same.

    I tried setting a function to remove all pieces and calling that before closing but still seems to do it. And the actual sprite prefabs don't disappear if I set breakpoints.

    So looks like I need to close all pieces and their equivalent level pieces/sprites down before going back to the menu scene.

    Although I still dont really understand why it all needs to be closed down. I thought stuff would just persist between scenes? Or is this what was mentioned earlier where the list persists but the items within it dont?

    One to look at tomorrow. Nearly there. ...
     
    Last edited: Jan 13, 2018
  21. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Still getting nowhere with this.
    Although I did have a 'doh' moment.

    I was loading a mainmenu scene. Then opening my scene2.
    In scene2 I was running the levelgenerator to create a list of levelPieces.
    That was all working, my issues was when I came back to the mainmenu and I got the object destroyed message.

    Then it dawned on me that in my mainmenu I hadn't created my levelpiece or levelGenerator object, beacuse I dont need them there, its not part of the game. But I guess if they aren't there, it cant keep them alive.

    So I tried creating the LevelPiece object and the LevelGenerator object in my main menu also.

    Now this means when I run the main menu, I get all my levelpieces created (on my menucanvas by default, I'll need to move them onto my other canvas for display later)

    However, when clicking the button to go through to scene2 it dies with my favourite error message.

    MissingReferenceException: The object of type 'LevelPiece' 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.

    It does this as soon as any object in scene2 tries to access the List that was created in the menu scene, eg
    Code (csharp):
    1.  
    2.     void MoveTowards(){
    3.         float step = speed * Time.deltaTime;
    4.         // Check to make sure we should be moving towards
    5.         if (LevelGenerator.instance.pieces[currentTarget].displayOnly == true){
    6.             // Move on to next piece
    7.             IncrementCurrentPiece ();
    8.             }
    9.             target = LevelGenerator.instance.pieces[currentTarget].transform.position;
    10.  
    11.  
    So where previously I was creating the List of objects in scene2 and they were vanishing when going back to mainmenu, I've now got the opposte issue in that they create in mainmenu scene and die when going to scene2.

    I'm sure there is something really simple stopping this from working, but I have no idea.
    Can someone please look at this code and let me know what I'm doing wrong. I know its a silly newbie mistake, but I cant work it out. I tried splitting it as below so the declaration only is done in mainmenu, and in scene2 it does all the work on it, but it still seems to fail.

    I just dont know how to keep this list of object persistant through the 2 scenes.

    Please help me. This is driving me mad now.
    Thanks

    LevelGenerator Class:
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. public class LevelGenerator : MonoBehaviour {
    8.     public static LevelGenerator instance;
    9.     public Transform levelStartPoint;
    10.     public  List<LevelPiece> pieces = new List<LevelPiece> ();
    11.     public  List<TextPiece> textPieces = new List<TextPiece> ();
    12.     public LevelPiece LevelPiece;
    13.     public TextPiece TextPiece;
    14.     private StandardVars standardVars = new StandardVars();
    15.     private int lastPiece;
    16.  
    17.  
    18.     void Awake() {
    19.         if (instance == null) {
    20.             DontDestroyOnLoad (gameObject);
    21.             instance = this;
    22.         } else {
    23.             if (instance != this) {
    24.                 Destroy (gameObject);
    25.             }
    26.         }
    27.     }
    28.  
    29.     void Start () {
    30.         if (Application.loadedLevel ==0) {
    31.             //lastPiece = 0;
    32.             GenerateInitialPieces ();
    33.             GenerateTextPieces ();
    34.             PrintValues ();
    35.         }
    36.         if (Application.loadedLevel >=1) {
    37.         //Debug.Log ("Calling Sprite Update");
    38.             UpdateSprites ();
    39.         }
    40.             }
    41.  
    42.  
    LevelPiece CLass
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class LevelPiece : MonoBehaviour {
    7.     void Start () {
    8. // Just variable definitions
    9. etc
    10. etc
    11.     }
    12.    
    13.     // Update is called once per frame
    14.     void Update () {
    15.        
    16.     }
    17.     void Create () {
    18.  
    19.     }
    20. }
    21.  
     
  22. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    So, I think maybe I know what's wrong now that I'm reading this, again.

    The list of objects are just on their own, right? If you want the list of objects to persist, they must either be parented to a root game object that has DontDestroyOnLoad (or they themselves must have DontDestroyOnLoad).
    Having them in a list, on a game object using DontDestroyOnLoad, is not enough to keep them around.
     
  23. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Thanks, that sounds quite possible.
    The list is just created within my LevelGenerator class, as any other variable would be - as above.

    Unfortunately I'm way out of my depth and dont quite understand exactly what you mean by 'parented to a root gameobject"

    I've tried a few things, but not got anywhere.

    And is it the list I need to parent (i.e. pieces) , or is it the objects in the list i.e. LevelPiece?

    Are you able to point me at any tutorials to this? I've tried google but not found anything of use, that I understand.

    Incidentally, I tried adding:
    Code (csharp):
    1.  
    2. void Awake(){
    3.         DontDestroyOnLoad(this.gameObject);
    4.     }// Use this for initialization
    5.  
    to my levelpiece.cs script.
    My exit button from scene2 now goes back to the main menu, without error. On the surface this seems a good thing.
    My LevelPieces seem to remain intact, but I cannot click anything on the main menu.

    I cant tell if this is good news or not. It looks like debug messages from scene2 are still being written, indicating that even though I am back at the mainmenu screen visually, I am actually still running components of scene2.

    In fact, if I stick a some Debug.Log output on the start game button of the main menu, clicking it doesn't even output anything. So its like it never actually returns back from my scene2.

    One other thing, I'm still using Application.LOadLevel. Is that likely to be causing issues now it has been superceded by SceneManager.?

    Thanks
     
  24. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I would switch to SceneManager just because. I don't think that would break anything, but I would stop using it ( get out of the habit) :)

    Okay, so what I was suggesting was that you could put that DontDestroy on each piece, or you could add every piece to 1 (say empty gameobject), as a child.
    Root, meaning it has no parent game object. Only root game objects can execute "DontDestroyOnLoad" (but take their children with them.. if that makes sense lol)


    Let's say your code may be working, if I were you maybe I would try to hide the parent object (or each one individually, if you don't parent them) when you load your menu scene or whatever.
    Then , see if you can interact properly with said scene.
    * hide .. disable.. whatever. :)
     
  25. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Thanks once again.

    I've changed to SceneManager but it is just the same.

    Just stepping back and trying to think this through a little.

    Several days ago I responded to this thread because I was getting the error about objects being destroyed when I went back to the main menu.

    So we've spent several days getting my objects to persist so they don't get destroyed when I go back to the main menu, and I don't get the error.

    But now we have the issue where I go back to the main menu and it doesn't respond, yet I can still see functions and objects of my scene2 working in the background and writing to Debug.Log. So it looks like it has visually gone back to my menu, but scene2 hasn't closed down.

    So actually, and correct me if I'm wrong, the issue isn't around scope and not destroying objects, its because scene2 isn't fully unloading when I move back to the menu? Is that not my 'real' issue here?

    The docs seem a little sparse, but from what I can find:
    https://www.alanzucconi.com/2016/03/23/scene-management-unity-5/

    It does mention:
    Ghost scenes. Every time you load a new level with SceneManager.LoadScene, Unity flushes all the scenes that have been previously loaded. Only game objects that invoked DontDestroyOnLoad (documentation) survive the process. This means that you can potentially use LoadScene, yet having all the previous scenes still loaded. Despite this, Unity will fail to realise that those scenes are actually still alive.

    I've no idea whether I'm seeing that issue, or whether I'm just misunderstanding what the scene opening and closing should do, and how it works.

    As a beginner I'm pretty amazed that I've learned enough to get my game working (by developing it effectively in scene2) then I'm having all this trouble simply adding a main menu with 'Start Game' on the front of it. That would seem to be basic functionality.

    So I'm even more confused than ever.
    EDIT: On reflection, I wonder if I've made too much stuff not destroy, trying to get around the initial issue. In particular my player/aeroplane sprite is now a singleton and not destroy. Perhaps it just needs to be singleton without the donotdestroy, and that is holding things open. More stuff to play with tonight, although I'm still confused that adding a menu is is as troublesome as it has been. All I really want is an option to just close everything down and start again. I'd be happy.
     
    Last edited: Jan 15, 2018
  26. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Finally I have some good news :)
    For me, and possible even more so for you guys:D

    It seems I was right on my previous post, and I've overdone the DontDestroyOnLoad stuff.
    The UIManager script on the menu was the issue causing the button not to work when it went back.
    So I left as singleton but commented the dontdestroy line and thats working.

    Scene2 was still doing the updates on the console so I then went round the other stuff I've done, and removed from there, and that also didn't break anything.

    So after all that, it looks like it was just the individual levelPieces that needed dontdestroy on load. Looks like I made it worse by trying to add others rather than better.

    I cant say I fully understand, but most importantly it is working.

    Many thanks again, and hopefully for a last time. I really appreciate the time you've taken to help with this issue.
     
  27. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    lol after reading all of that, I'm glad that you arrived at a working solution. Good stuff :)
     
  28. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Unfortunately the next stage will be moving a lot of the level generation into the main menu, so I can have multiple levels and control over them.

    I have a bad feeling I may have similar issues again but at least I have a slightly better grasp of how this works now.

    Wish me luck ...
     
  29. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Keep only what you need and perhaps if it gets to be too much, it might be an option to save & reload it (if the scenes aren't all active at once, anyways).

    Whatever happens -- Good luck :)
     
  30. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    Thanks.

    I don't actually need to keep much between levels at all, and I had already considered saving it out from the menu and loading it back in at scene2. It seems a bit silly, but I suspect that is the best way to do it.

    To recap, I have a level generator on scene2, which is just hard coded creating items in a list. I'm at prototype stage now.

    What I need to do now is on main menu have a 'select level' option where I can pick one of say 10 levels and create a list of gameitems for use in scene2.

    The level generator on scene2 will then have to be amended so instead of creatng a list of items based on hard coded values it either a) reads the list of items from the list variables in the main menu scene and duplicate them into its own list or b) reads them in from disk if I save the list temporarily to disk from the main menu.

    Given the issues I had with stuff persisting and/or not persisting I'm inclined to just select the level and save the pieces out to disk on the mainmenu scene, and then just read it all in from disk on the scene2 game scene. I can treat the two as almost completely separate then, and just destroy everything in scene2 when we go back.

    Is there anything radically wrong with that approach? I like it as once I've amended scene2 to create the list of objects from disk rather than from card coded values, I can leave that alone and not risk breaking it by adding functionality to the main menu.

    Thanks once again for the input, you truly have the patience of a saint. :D
     
  31. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I see. I didn't realize that only one of the levels would be keeping data, and just between the main menu and itself (though it may be reading data from another level).

    To be honest, I don't totally understand what you're saying. 1 of 10 levels can decide what is built in scene2 - that's what I understood. If by any chance those are just 'values' (not game objects), that makes things easier, as you can simply 'bring' that information with you when you go to scene 2.
    If it's just the active scene you want to keep active, as you transition from scene 2 to the menu (and back), then keeping the items in DontDestroy sounds perfectly okay (and hidden).

    If you plan to save between play sessions, also, though, you will want to know how to save the current game, anyways.

    Sorry I'm not always understanding everything right away. I'm certain it's all crystal clear to you :) heh.

    As for always saving vs. keeping some things not destroyed (you said it's not even a lot), I would say that between scenes, and if it's not a lot, the difference is minimal; at the same time, though, there's nothing to be scared of of keeping it not destroyed..

    Hope that semi-complete, semi-vague response helps a bit lol
     
  32. newcoder17

    newcoder17

    Joined:
    Dec 9, 2017
    Posts:
    103
    You and me both unfortunately.
    I'll have a play and look at my options.

    I think my problem is I've gone full on into a project, as a first project, without having had the time to really get to grips with Unity, c# or programming in general. In an ideal world I would have had more time to spend on the basics and groundwork, but such is life.
     
  33. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I'm always recommending that to people :) heh.

    I understand wanting to dive in. Happens to me, too. But taking some time to build up helps a lot..
     
    newlightgame01 likes this.
  34. newlightgame01

    newlightgame01

    Joined:
    Dec 8, 2015
    Posts:
    3
    Hello, i have same issue. after reload scene, some object missing reference. Please tell me your skype name @methos5k
     
  35. rmurdoch_unity

    rmurdoch_unity

    Joined:
    Jul 17, 2019
    Posts:
    1
    Hey guys,

    This is observer pattern, the event is still looking for the subscribed object.

    Simply unsubscribe when you no longer need it to avoid errors.

    private void OnDisable()
    {
    SomeClass.ThingsYouAreListeningFor -= MethodSubscribing;
    }
     
    Setting_Sun and plasmanunchucks like this.
  36. MercurialKid

    MercurialKid

    Joined:
    Aug 30, 2018
    Posts:
    22
    +1 YaserDev. Was looking for that one for ages!
     
    YaserDev likes this.
  37. tomatohorse

    tomatohorse

    Joined:
    Oct 26, 2013
    Posts:
    13
    Thanks to all who mentioned unsubscribing to event listeners. Doing that on my GameManager right before reloading the scene fixed this problem for me.
     
  38. Cryo_Quantom

    Cryo_Quantom

    Joined:
    Sep 20, 2018
    Posts:
    1
    This actually saved me from a bunch of issues, thank you so much!!
     
    YaserDev likes this.
  39. uzisho

    uzisho

    Joined:
    Jul 3, 2019
    Posts:
    14
    FWIW - I've been having this problem as well and solved it with what I think is a rather simple solution.
    When the object gets destroyed - simply remove the the listener:

    Code (CSharp):
    1.     void Start()
    2.     {
    3.         Object.onEvent += event;  
    4.     }
    5.  
    6.  
    7.     void OnDestroy()
    8.     {
    9.         Object.onEvent -= event;
    10.     }
     
  40. Foxsocks79

    Foxsocks79

    Joined:
    Nov 11, 2013
    Posts:
    4
    This is most likely the cause of the problem. Another alternative is to add/remove the listeners on the "OnEnable" or "OnDisable"