- Home /
Problem transferring children to a new parent
Hi
I'm trying to transfer all the children of an object to a new parent. The code below does not transfer all the items, it is skipping over some of them (explanation below)
// Loop through all the children in old_parent and move them to new_parent
foreach (Transform child in old_parent.transform) {
Debug.Log("moving object: " + child.name);
child.SetParent(new_parent.transform, false);
}
However if I comment out the line changing the Parent, it does loop over every child
// Loop through all the children in old_parent and move them to new_parent
foreach (Transform child in old_parent.transform) {
Debug.Log("moving object: " + child.name);
// child.SetParent(new_parent.transform, false);
}
I do get the name of all the children.
I think this is the typical problem when you change the list (or array) you are iterating over. In pseudocode
original list [A, B, C]
the loop starts
go fetch the element at position 0 (A)
remove it, now list is [B, C]
next iteration of the loop
go fetch element at position 1 (and now this is C and not B)
the list is [B]
I usually solve this problem iterating backwards from the end of the list but don't know how to do it in c# with game object.transform
Any ideas?
Answer by zach-r-d · Jun 20, 2015 at 01:16 AM
Manual reverse iteration is possible using the GetChild() and childCount variables:
for (int i=old_parent.childCount-1; i >= 0; --i) {
Transform child = old_parent.GetChild(i);
Debug.Log("moving object: " + child.name);
child.SetParent(new_parent.transform, false);
}
Additionally, this method performs no allocations, which is a nice bonus!
btw: The Enumerator that Transform implements actually does the same thing but forward ^^.
For sure! It's just that it allocates an instance of the Transform.Enumerator class in the process (wonder why it isn't a struct?).
Well, mutable structs are actually something very evil ^^. .NET / $$anonymous$$ono implements most iterators for the generic classes as structs.
I found it quite suprising and interesting that the C# compiler doesn't actually use the IEnumerable interface when in comes to foreach loops. Just as fallback. That's the reason a struct enumerator actually works. If it would be based on the IEnumerable interface the actual struct would be boxed because interfaces are always reference types. The compiler actually does code analysis to deter$$anonymous$$e if a class actually implements the needed methods and calls those directly ins$$anonymous$$d of using an interface.
On the other hand Eric Lippert also suggest to not use mutable structs unless it's really necessary. See this and this as well.
Ah, interesting! That explains how it's possible to have an enumerator for primitive types without boxing, in addition to how the enumerators themselves don't get boxed if they're value types. Good to know about the dangers of mutable types, too! That $$anonymous$$utating Readonly Structs post is crazy.
I'd completely forgotten about this until now, but sadly, the old version of $$anonymous$$ono that Unity uses under the hood will apparently box enumerator-structs in this case anyway. Even in 5.1.1f1, checking the mono version yields "2.0". Yeesh.
(For the record though, I support the use of foreach anyway because I$$anonymous$$O the paltry performance penalty doesn't offset the value of significantly cleaner code)
Answer by JokerZappie · Mar 24, 2017 at 12:16 PM
A simple while loop like this does the trick too:
Transform newParent = someTransform;
Transform oldParent = someTransform;
while (oldParent.childCount > 0) {
oldParent.GetChild(oldParent.childCount - 1).SetParent(newParent, false);
}
This iterates from the last/highest entry to the first/lowest entry.
Note that this puts all children in reversed hierarchy order into the new parent, so the first child becomes the last child.
Your answer
Follow this Question
Related Questions
Make a simple tree 1 Answer
Object scale/rotation changes when parented to flipped object 0 Answers
undoing parenting of object's transform 1 Answer
Separate child rotation 1 Answer
Assign parent object to target 2 Answers