Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Iterating through Children: Why isn't this working?

Discussion in 'Scripting' started by Nanako, Jul 28, 2015.

  1. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    Brief intro, here's the hierarchy i'm working with. Note the many duplicate "Manipulator...." objects several layers deep.




    I'm attempting to programmatically delete them all and then replace them with a single clean one
    (yes i know this is easy to do manually. I'm writing a tool for automating things)

    The section of relevant code for this is

    Code (CSharp):
    1. void SetupManipulators()
    2.     {
    3.         for(int i  = 0; i < ManipulatorParentNames.Length; i++)
    4.         {
    5.             string s = ManipulatorParentNames[i];
    6.             Transform t = ObjectTools.FindChildByName(s, transform);
    7.  
    8.             foreach (Transform v in t)
    9.             {
    10.                 Debug.Log("Checking: " + v.gameObject.name);
    11.                 if (v.gameObject.name.ToLower().Contains("manipulator"))
    12.                 {
    13.                     Debug.Log("Destroying: " + v.gameObject.name);
    14.                     DestroyImmediate(v.gameObject);
    15.                 }
    16.             }
    17.  
    18.             GameObject g = Instantiate(manipulator);
    19.             g.transform.parent = t;
    20.             g.transform.localPosition = ManipulatorLocalPositions[i];
    21.         }
    22.     }
    There are some references to arrays and functions there. ManipulatorParentNames currently only contains one word, "Jaw"

    Here's the debug output from running that code, on that hierarchy (setup complete is in the function that called this one)



    And how the hierarchy looks afterwards



    What the devil is going on here?
    As can be clearly seen, it checks the first and second child, but then skips every alternating one starting from the third.

    Explain this madness please ;-;
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I'm guessing the "stack is falling"... i.e.
    get 1 delete 1 => 2 becomes 1 mwhahahah I'm not going to get deleted, 3 become 2, 4 become 3 etc.
    get 2 delete 2 => 1 is still 1, 3 becomes 2 mwhahahah I'm not going to get deleted, 4 becomes 3 etc.


    so a while loop removing the first one until the length is empty would work
     
    Nanako likes this.
  3. OwenG

    OwenG

    Joined:
    Sep 30, 2013
    Posts:
    20
    When you call DestroyImmediately from inside your foreach loop, I suspect it's messing with the loop iterators because you're immediately removing the child from the hiearchy. To do a safe delete, you'd want to do something like:

    Code (CSharp):
    1. List<Transform> toBeDeleted = new List<Transform>();
    2. foreach (Transform v in t)
    3. {
    4.     Debug.Log("Checking: " + v.gameObject.name);
    5.     if (v.gameObject.name.ToLower().Contains("manipulator"))
    6.     {
    7.         toBeDeleted.Add(v);
    8.     }
    9. }
    10. for (int i = 0; i < toBeDeleted.Count; i++)
    11. {
    12.     var v = toBeDeleted[i];
    13.     Debug.Log("Destroying: " + v.gameObject.name);
    14.     DestroyImmediate(v.gameObject);
    15. }
    16. toBeDeleted.Clear();
    Hope that helps.
    Owen
     
    Kiwasi and Nanako like this.
  4. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    I tried it myself and maybe just a little change will help. I don't know exactly how you have implemented it, i'll give it a try.

    if this gives you back the Transfrom "Jaw" in your hierarchy

    than i only changed

    Code (CSharp):
    1. void SetupManipulators()
    2.     {
    3.         for(int i  = 0; i < ManipulatorParentNames.Length; i++)
    4.         {
    5.             string s = ManipulatorParentNames[i];
    6.             Transform t = ObjectTools.FindChildByName(s, transform);
    7.             Transform[] allTransfomrsInJaw = t.gameObject.GetComponentsInChildren<Transform>();
    8.  
    9.             foreach (Transform v in allTransfomrsInJaw)
    10.             {
    11.                 Debug.Log("Checking: " + v.gameObject.name);
    12.                 if (v.gameObject.name.ToLower().Contains("manipulator"))
    13.                 {
    14.                     Debug.Log("Destroying: " + v.gameObject.name);
    15.                     DestroyImmediate(v.gameObject);
    16.                 }
    17.             }
    18.             GameObject g = Instantiate(manipulator);
    19.             g.transform.parent = t;
    20.             g.transform.localPosition = ManipulatorLocalPositions[i];
    21.         }
    22.     }
    Tried it out in an CustomEditorScript. Because i couln't find the ObjectTools class i made something different.

    Code (CSharp):
    1. void SetupManipulators()
    2.     {
    3.         for(int i  = 0; i < ManipulatorParentNames.Length; i++)
    4.         {
    5.             string s = ManipulatorParentNames[i];
    6.             GameObject t = GameObject.Find(s);
    7.             Transform[] allTransfomrsInJaw = t.GetComponentsInChildren<Transform>();
    8.  
    9.             foreach (Transform v in allTransfomrsInJaw )
    10.             {
    11.                 Debug.Log("Checking: " + v.gameObject.name);
    12.                 if (v.gameObject.name.ToLower().Contains("manipulator"))
    13.                 {
    14.                     Debug.Log("Destroying: " + v.gameObject.name);
    15.                     DestroyImmediate(v.gameObject);
    16.                 }
    17.             }
    18.             GameObject g = Instantiate(manipulator);
    19.             g.transform.parent = t;
    20.             g.transform.localPosition = ManipulatorLocalPositions[i];
    21.         }
    22.     }
     
    Last edited: Jul 28, 2015
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The other option is to iterate through the loop backwards. That way none of the indexers get mixed up as you remove children.
     
    DonLoquacious and martinmr like this.