Search Unity

How to destroy instantiated GameObjects from a List? Please respond.

Discussion in 'Scripting' started by markashburner, Jun 14, 2018.

  1. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    Hi

    I am trying to destroy instantiated gameObjects from a List.

    So I have added the instantiated GameObjects to a list...but I want them to be destroyed when they reach a certain distance from the camera, as it is pointless for them to be there when they are not in view of the camera.

    This is the code I have so far...if I use Destroy or DestroyImmediate, it throws me errors.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. namespace QuadtreePlanet.Foliage
    6. {
    7.     public class PlanetFoliageObjects : MonoBehaviour
    8.     {
    9.         public Transform mainCamera;
    10.         public float maxLod;
    11.         public List<GameObject> foliageObjects;
    12.      
    13.    
    14.  
    15.         // Update is called once per frame
    16.         void Update()
    17.         {
    18.             if (foliageObjects != null)
    19.             {
    20.                 foreach (GameObject objects in foliageObjects)
    21.                 {
    22.                     float distance = Vector3.Distance(objects.transform.position, mainCamera.transform.position);
    23.  
    24.                     if (distance > maxLod)
    25.                     {
    26.                         DestroyImmediate(objects, true);
    27.                     }
    28.  
    29.                 }
    30.             }
    31.          
    32.         }
    33.     }
    34.  
    35.  
    36. }
    The error it throws me is this:
    MissingReferenceException: The object of type 'GameObject' 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.

    Can someone help me to work this out?

    Thanks
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    You don't remove the object from the list, so you're trying to delete it every frame. So you delete it when it gets too far away, and then the next frame you're trying to check if it's too far away again.

    Also don't beg in your post title, that's just sad.
     
    Ignacii likes this.
  3. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    Ok so I have tried removing it from the list and I still get the same error.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. namespace QuadtreePlanet.Foliage
    6. {
    7.     public class PlanetFoliageObjects : MonoBehaviour
    8.     {
    9.         public Transform mainCamera;
    10.         public float maxLod;
    11.         public List<GameObject> foliageObjects;
    12.      
    13.    
    14.  
    15.         // Update is called once per frame
    16.         void Update()
    17.         {
    18.             if (foliageObjects != null)
    19.             {
    20.                 for (int i = 0; i < foliageObjects.Count; i++)
    21.                 {
    22.                     float distance = Vector3.Distance(foliageObjects[i].transform.position, mainCamera.transform.position);
    23.  
    24.                     if (distance > maxLod)
    25.                     {
    26.                         DestroyImmediate(foliageObjects[i], true);
    27.                         foliageObjects.Remove(foliageObjects[i]);
    28.  
    29.                     }
    30.                 }
    31.             }        
    32.         }
    33.     }
    34.  
    35.  
    36. }
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    if you're doing this because you think it'll make your game "more optimal" it might not be as much of a benefit as you may think. Renderers will already be efficiently culling the objects that can't be seen, and destroy/instantiate incurs a fair amount of garbage/memory management which is something "optimisation" usually tries to avoid.

    As always, use the profiler to see if it's actually an issue before trying to "solve" something that isn't actually causing problems :)

    https://unity3d.com/learn/tutorials/temas/performance-optimization/profiler-window

    If it's more a "once it's out of camera it's never ever coming back" situation you might want to look into object pooling rather than using the instantiate/destroy cycle.
     
  5. Tset_Tsyung

    Tset_Tsyung

    Joined:
    Jan 12, 2016
    Posts:
    411
    I think your latest issue is the you need to execute these 2 commands in the opposite order. Remove it from the list first, and then destroy it. (Totally prepared to be wrong on this, though)

    I agree with LeftyRighty, destroying objects isn't as optimal as you may think. If the object COULD be reused later, then pool it.

    Also, if you're REALLY keen on optimising, I believe that foreach is not as performant as a for loop. Use a for loop, but make sure that the declaration for the 'object' is outside the for loop else you're just keeping making loads of object references.
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Some things:

    - do the for-loop in reverse if you're removing things from the list as you're iterating it. Otherwise you skip elements. If it's not immediately obvious why you'd skip elements, try sit down with a pen and paper and step through the for-loop to see how it runs.

    - Don't do DestroyImmediate at runtime. Destroy is much better. Destroy waits until the end of the frame to destroy the thing, which circumvents a lot of issues that pop up when you suddenly yank something straight out of the game.

    - Post the line errors happen on if you want help with errors.
     
    Tset_Tsyung likes this.
  7. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    It instantiates objects on the fly at run-time and continuously instantiates. It runs perfectly fine at the beginning at 70 fps but as the game continuous for 10 to 30 minutes, the FPS gradually starts to drop. That's why I need to destroy some of the objects otherwise I will literally have tens of thousands of them without destroying them.

    Does object pooling remove the objects? Or just disables them?
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    object pooling would entail reusing the objects. So instead of destroying them, you disable them, and if there's any disabled ones when you need a new one, you enable one of those instead of instantiating.

    There's a bunch of tutorials and libraries and whatnot for how to do it, most of them are bad. I'd recommend just trying to do it on your own.
     
  9. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Why not use LOD and have the LOD cull the object?