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

Finding all child objects NOT of a type with a name containing a string

Discussion in 'Scripting' started by ATLAS-INTERACTIVE, Oct 14, 2016.

  1. ATLAS-INTERACTIVE

    ATLAS-INTERACTIVE

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    I have a List of meshes (GameObjects actually) which holds all meshes generated by a script, the problem is that I need to be able to duplicate some of them and move them around manually in the editor, so I created a custom editor to add a button to call a function (AddNewToMeshArray), but it doesn't seem to have done the trick.

    What I need to do is look through all the child objects of the script and see if their name starts with "PointPlane" and ensure it doesn't have the component LightStripNode, then add this object to the meshes list.

    I thought the code below would do it but it doesn't seem to have, as when I clear the list (iterate through it and use DestroyImmediate(meshes)) the ones I duplicated are left behind, so they were never added.

    Code (CSharp):
    1. public List<GameObject> meshes = new List<GameObject>();
    2.  
    3. public void AddNewToMeshArray()
    4.     {
    5.         LightStripNode[] lsnodes = GetComponentsInChildren<LightStripNode>();
    6.  
    7.         for (int i = 0; i < lsnodes.Length; i++)
    8.         {
    9.             /*if (!lsnodes[i].GetComponent<LightStripNode>())
    10.             {*/
    11.             if(NameContains("PointPlane", lsnodes[i].gameObject.transform))
    12.             {
    13.                 meshes.Add(lsnodes[i].gameObject);
    14.                 Debug.Log(lsnodes[i].name);
    15.             }
    16.         }
    17.     }
    18.  
    19.     static GameObject NameContains(string start, Transform transf)
    20.     {
    21.         if (transf.name.StartsWith(start))
    22.         {
    23.             return (transf.gameObject);
    24.         }
    25.         else
    26.         {
    27.             return null;
    28.         }
    29.     }
    Is there something I am missing, or have I just done it all wrong?
     
  2. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    154
    Where does your nameContains return the gameobject`to? It's actually a bool statement lol.

    Code (CSharp):
    1. public void AddNewToMeshArray()
    2.     {
    3.         LightStripNode[] lsnodes = GetComponentsInChildren<LightStripNode>();
    4.  
    5.         for (int i = 0; i < lsnodes.Length; i++)
    6.         {
    7.             bool containsName = lsnodes[i].gameobject.name.StartsWith("PointPlane") ? true : false;
    8.  
    9.             if (containsName)
    10.             {
    11.                 meshes.Add(lsnodes[i].gameObject);
    12.                 Debug.Log(lsnodes[i].name);
    13.             }
    14.         }
    15.     }
     
  3. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    To be more specific, unlike C, and maybe c++ this code is not valid:
    Code (CSharp):
    1. MyClass   classInstance = new MyClass();
    2. //  or set it to null
    3. // MyClass  classInstance = null;
    4.  
    5. if (classInstance)
    6.      Debug.Log("true");
    7. else
    8.      Debug.Log("false");
    9.  
    Which is what your code is doing. Your returning the actual GameObject or null. You can't do an if statement on it in C#. To be honest with you I'm surprised you didn't get an error staying it couldn't convert Something from a GameObject to a bool.

    You can follow the code @Kamil-Says posted or change NameContains to return a bool, and just return true/false there which seems simpler and what you would expect from a static function like that. I mean there is no reason for it to return the GameObject you passed in.. you already have that reference, you just need true/false on the name checking.
     
  4. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,950
    Actually, you can do that with a gameobject (and a few other internal classes that inherit from Object, like transform, rigidbody, etc).
    You can use a bool operator on a gameobject, it will return true if it exists or false if it doesn't.

    Correct, by default, that wouldn't work. However if you add an implicit operator, you can make it work. If your class looks like this:

    Code (CSharp):
    1. public class MyClass
    2. {
    3.     public int foo;
    4.     public string bar;
    5.    
    6.     public static implicit operator bool(MyClass t)
    7.     {
    8.         return(t!=null);
    9.     }
    10. }
    Your if statement will now work.
     
    takatok likes this.
  5. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,950
    You can also take it bit further:
    Code (CSharp):
    1. public class GenericTestScript : MonoBehaviour
    2. {
    3.     MyClass test_class;
    4.     MyClass test_empty_class;
    5.     string log;
    6.    
    7.     void Start()
    8.     {
    9.         // check a new class
    10.         log="New Class with assigned values:\n";
    11.         test_class = new MyClass(5,"Zaphod");
    12.  
    13.         int test_int = test_class + 22;
    14.         float test_float = test_class + 1.2345f;
    15.         log+="\t int:"+test_int+"\n";
    16.         log+="\t float:"+test_float+"\n";
    17.         log+="\t string:"+test_class+"\n";
    18.        
    19.         //check an empty class
    20.         log+="Empty class:\n";
    21.         test_empty_class = null;
    22.        
    23.         test_int = test_empty_class + 22;
    24.         test_float = test_empty_class + 1.2345f;
    25.         log+="\t int:"+test_int+"\n";
    26.         log+="\t float:"+test_float+"\n";
    27.         log+="\t string:"+test_empty_class+"\n";
    28.        
    29.         Debug.Log(log);
    30.     }
    31. }
    32.  
    33. [System.Serializable]
    34. public class MyClass
    35. {
    36.     public int foo;
    37.     public string bar;
    38.     public Color material_color;
    39.    
    40.     public MyClass(int f, string b)
    41.     {
    42.         foo = f;
    43.         bar = b;
    44.     }
    45.    
    46.     public MyClass()
    47.     {
    48.         foo = 0;
    49.         bar = "nothing";
    50.     }
    51.  
    52.     public static implicit operator bool(MyClass t)
    53.     {
    54.         return(t!=null);
    55.     }
    56.  
    57.     public static implicit operator int(MyClass t)
    58.     {
    59.         return (t!=null) ? t.foo : 0;
    60.     }
    61.    
    62.     public static implicit operator float(MyClass t)
    63.     {
    64.         return (t!=null) ? (float)(t.foo) : 0f;
    65.     }
    66.  
    67.     public static implicit operator string(MyClass t)
    68.     {
    69.         return (t!=null) ? t.bar : "empty";
    70.     }
    71. }
    72.  
    Returns:
    Code (CSharp):
    1. New Class with assigned values:
    2.      int:27
    3.      float:6.2345
    4.      string:Zaphod
    5. Empty class:
    6.      int:22
    7.      float:1.2345
    8.      string:empty
     
  6. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,950
    It seems to work generally. Though since you are adding to the list every time, it is possible to have orphans in the list. If you add:
    Code (CSharp):
    1. meshes = new List<GameObject>();
    At the beginning of the method, it will ensure that the list only reflects the actual ones that are under the parent. It may also be in how you are destroying them. I just used same logic for deleting. (rather than the list as a reference):
    Code (CSharp):
    1.     void deleteMeshes()
    2.     {
    3.         TestObjList script = (TestObjList)target;
    4.         LightStripNode[] lsnodes = script.gameObject.GetComponentsInChildren<LightStripNode>();
    5.  
    6.         for (int i = 0; i < lsnodes.Length; i++)
    7.         {
    8.             if(TestObjList.NameContains("PointPlane", lsnodes[i].gameObject.transform))
    9.             {
    10.                 DestroyImmediate(lsnodes[i].gameObject);
    11.             }
    12.         }
    13.         // update it afterward to keep the list in sync
    14.         script.AddNewToMeshArray();
    15.     }
    16.  
    It seems to work as expected.