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. Dismiss Notice

There is a GameObject is in a Stack, how to detect if it has been destroyed?

Discussion in 'Scripting' started by Angry-Water, Jun 22, 2014.

  1. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    Hi, Guys,

    I know we can check a GameObject is null or not to detect if it has been destroyed, BUT, sometime we can NOT so sure, such as, a GameObject pushed in a Stack (Or Queue, ArrayList....etc.).

    It could be destroyed but NOT null.

    How to detect a non-null GameObject if it has been destroyed.

    I have written codes below, it will report accessing destroyed object almost every time:

    Code (CSharp):
    1.         public void ClearAll()
    2.         {
    3.     //vault is a Stack of C#
    4.             foreach ( object obj in vault )
    5.             {
    6.                 if ( obj == null ) continue;
    7.  
    8.                 if ( obj is Component )
    9.                 {
    10.                     GameObject.Destroy( ( ( Component ) obj ).gameObject );
    11.                 }
    12.                 else
    13.                 {
    14.                     GameObject.Destroy( ( GameObject ) obj );
    15.                 }
    16.             }
    17.  
    18.             vault.Clear();
    19.         }
    20.  
     
  2. glacius3000

    glacius3000

    Joined:
    Oct 5, 2012
    Posts:
    69
    According to Unity's API . Destroy doesn't destroy until the CURRENT update loop is done executing. that means you have the same gameobject (or its components) in vault more than once. You're either gonna have to find a better way to store your objects (I would go with this method). OR you can add the objects (as Objects) to a HashSet, remove them from the vault. then delete all the items in the HashSet in a separate loop.

    HashSets store unique lists of items. That means the same Object can not be added more than once.
     
    Angry-Water likes this.
  3. AngryAnt

    AngryAnt

    Keyboard Operator Moderator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    C# operators are overloaded - not overridden. This means that their implementation is determined at compile time - not runtime, and so is decided by the type of the reference - not the object being referenced.

    In your case you are doing a null check on a variable of type object, which will invoke the == operator as defined for System.Object, the functionality of which is to check if the actual reference is equal to null, which it will not be for a reference to a destroyed GameObject.

    To achieve the functionality you want, you need to also perform a null check with a reference of type GameObject, thus invoking the == operator as defined for GameObject, the functionality of which is to also equal null if the GameObject has been destroyed.

    One example could be:
    Code (csharp):
    1. if( obj ==null || (obj is GameObject && (GameObject)obj == null ) )continue;
     
    Angry-Water likes this.
  4. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    Another simpler and slightly more efficient expression to achieve this is:
    Code (csharp):
    1.  
    2. if (obj as GameObject == null) continue;
    3.  
     
    Angry-Water likes this.
  5. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58

    Okay~~~ HashSets is cool for my another purpose for the "Homing Missile" function to identify foes. Thanks a lot.

    This Stack vault is for recycle objects which will reproduce again in very short time, so just been deactivated and stored here temporary.

    But I think I didn't destroy them over 1 time, just before change scene or quit program, U3D will auto-destroy them before I clear these object in the Stack with such codes.
     
  6. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    WOW, thank you so much.

    I think I got your point. Please tell me if I was wrong.

    As I know about your point, ( obj == null ) or ( obj is GameObject ) are just to make .Net check obj is an empty reference (like null pointer in C++) or check obj is a data structure built with class GameObject, right?

    And the ( ( ( GameObject ) obj ) == null ) will cause .Net try to convert its type as GameObject, but it will find this memory allocation was no longer available if it has been destroyed, so even the value in memory is not ZERO, but still return a "null" for the logic function "==".

    Am I right? ;)
     
  7. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    I see, thanks for help!

    I guess I need to check for 2 types of both Component and GameObject, because I have many different vaults but only 1 ClearAll() function. Or I had to make 2 different clear all functions.
     
  8. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    I don't know how you have defined your collection since you are using the following:
    Code (csharp):
    1.  
    2. foreach(object obj in vault )
    3.  
    I would guess that you are using something like List<object>. If your collection was storing UnityEngine.Object references then this would be simpler still since Unity's special '==' overload lives inside the UnityEngine.Object base class.
    Code (csharp):
    1.  
    2. public List<Object> vault;
    3.  
    4. ...
    5.  
    6. foreach (var obj in vault) {
    7.     // If game object, component, or whatever is not null... destroy!!
    8.     if (obj != null)
    9.         Destroy(obj);
    10. }
    11. vault.Clear();
    12.  
     
    Angry-Water likes this.
  9. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    Ok, these are my new codes for other developers who want to know the result, it works.

    Many thanks to you, pals. ;)

    Code (CSharp):
    1.     void ClearAll()
    2.     {
    3.         foreach ( object obj in vault )
    4.         {
    5.             try
    6.             {
    7.                 [SIZE=14px]if ( ( ( GameObject ) obj ) != null )[/SIZE]
    8.                 {
    9.                     GameObject.Destroy( ( GameObject ) obj );
    10.                 }
    11.                 else if ( ( ( Component ) obj ) != null )
    12.                 {
    13.                     GameObject.Destroy( ( ( Component ) obj ).gameObject );
    14.                 }
    15.             }
    16.             catch          //In case for "Type Conversion" failed
    17.             {
    18.                 continue;
    19.             }
    20.         }
    21.  
    22.         vault.Clear();
    23.     }
    24.  
     
  10. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    The vault is a Stack.

    It looks like more slightly, Destroy() is define as:
    Code (CSharp):
    1. public static void Destroy( Object obj );
    I think your codes looks brilliant, I can try it now, just for seconds.
     
  11. Angry-Water

    Angry-Water

    Joined:
    Sep 11, 2012
    Posts:
    58
    Ok, the result is good. :D

    It works!! Object.Destroy() will destroy all GameObject & Component.

    There are only points have to note:
    1. Object is ambiguous with UnityEngine.Object, so it must define clearly, or the Visual C# will complain.
    2. "foreach" will throw null in its collection of Stack, so detection of ( obj == null ) is still necessary. (when the class type is correct but the reference is null)
    3. Still a catch for safety.

    Code (CSharp):
    1.     void ClearAll()
    2.     {
    3.         foreach ( UnityEngine.Object obj in vault )
    4.         {
    5.             try
    6.             {
    7.                 if ( obj != null ) UnityEngine.Object.Destroy( obj );
    8.             }
    9.             catch
    10.             {
    11.                 continue;
    12.             }
    13.         }
    14.  
    15.         vault.Clear();
    16.     }
    17.  
     
  12. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    The try...catch should be redundant there...