|
Hi everyone, This little piece of code has a bug.
If we set the parent of a transform in a foreach loop of the parent, the next child is not enumerated. I know removing an item while enumerating is not generally a good idea. But Unity don't even throw a warning about that, either in the doc or at runtime. On the other hand, C# or Mono throws an exception when we do something like that. And I just spent an afternoon figuring why some object was correctly suppressed when some other doesn't while both of them pass the condition :-(.
(comments are locked)
|
|
A simple example depicting the suggestion put by Jessy.
Extra reading that is slowly but steadily going off topic ahead:You can make use of predicates to allow to unparent a child following an arbitrary test:
And use it as such:
And you can even make it a bit more reusable if you also provide an action so you can do other things that just unparenting them:
Then you could do: I seem to always overcomplicate it. Ugh. Just do with the first example :)
Mar 11 '11 at 05:47 PM
Statement ♦♦
(comments are locked)
|
|
Like you say, you're not supposed to change the object you are enumerating (in this case 'transform'). This should work:
You could use some fancy LINQ stuff if you want for the 'find' bit. While this probably works, its complexity is quite bad. For example, had you 50 children and the last 25 were the ones to be removed you'd end up iterating 26 * 26 (676) times, or so. Maybe 675 given the last time it wouldn't find any object.
Mar 11 '11 at 05:26 PM
Statement ♦♦
But a new and interesting approach I've never stumbled across. Memory usage is very low :)
Mar 11 '11 at 05:49 PM
Statement ♦♦
But practically speaking, I did some performance tests on this approach vs. using a list, and there is no noticable difference at all until you start to reach into the thousands. And if you're dealing with thousands of children chances are you have bigger problems to handle :)
Mar 11 '11 at 06:13 PM
Statement ♦♦
Yeah, it's quadratic, but, like you say, it will only become a problem when the number of children is really high. If you know that the children are 'vector-like', you can always do a single for-loop over the children and only increment the index when the child is not removed.
Mar 11 '11 at 06:24 PM
MvD
Or simpler: '...and don't increment the index when the child is removed'
Mar 11 '11 at 06:25 PM
MvD
(comments are locked)
|

There is no question here. Put the children into a List, first, and then operate on that.
The solution for this bug is obvious. But again it's easy to check if we are in a foreach loop when we access to the parent property. Then we can either throw an exception (simple solution which prevents time loss) or it could be managed (more complex but I think it can be done).
Ok I didn't see there were the GetChild and the GetChildCount methods like Statement says below (well it's not a surprise since they are not documented :-(). With these methods, a for loop can be used and I can manage the index myself.