GetChild out of range for index greater than 0
I'm trying to perform transforms on a large hierarchy of objects. But when I try to access a child with an index greater than 0 I get an out of bounds exception.
Perhaps I'm misunderstanding how the GetChild(#) function works, but other than some sort of odd bug I can't figure out what would prevent me from accessing these objects.
Here's my Hierarchy: 
And my Code:
{
public void MoveObjectsToListPosition()
{
//just to define how many times it should run ... also means it won't run outside a game save
for(int i = 0; i < this.transform.childCount; i++)
{
//Grabs the first object in the spawned star prefab
Transform star = this.transform.GetChild(i);
star.position = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z);
star.GetChild(0).position = new Vector3(star.position.x, star.position.y, star.position.z);
star.GetChild(0).GetChild(0).position = new Vector3(star.position.x, star.position.y, star.position.z);
Debug.Log("Moved Star " + i + " to " + star.position);
for(int j = 0; j < this.transform.GetChild(i).GetChild(0).GetChild(0).childCount - 1; j++)
{
//Grabs the second+ child after the "Star (Axes)" object (a planet)
Transform planet = star.GetChild(0).GetChild(0).GetChild(i + 1);
planet.position = new Vector3(star.position.x, star.position.y, star.position.z);
planet.GetChild(0).position = new Vector3(planet.position.x, planet.position.y, planet.position.z);
planet.GetChild(0).GetChild(0).position = new Vector3(planet.position.x, planet.position.y, planet.position.z);
Debug.Log("Moved Planet " + i + " " + j + " to " + planet.position);
for(int k = 0; k < (transform.GetChild(0).GetChild(0).childCount - 1); k++)
{
//Grabs the second+child after the "PlanetBody (Axes)" object (a satellite)
Transform moon = planet.GetChild(0).GetChild(0).GetChild(1 + k);
moon.position = new Vector3(planet.position.x, planet.position.y, planet.position.z);
moon.GetChild(0).position = moon.position;
moon.GetChild(0).GetChild(0).position = moon.position;
moon.GetChild(0).GetChild(0).GetChild(0).position = moon.position;
Debug.Log("Moved Moon " + i + " " + j + " " + k);
}
}
}
}
}
It seems to move the first planet just fine, but nothing else is being moved. Any help is appreciated.
Answer by Harinezumi · Apr 18, 2018 at 07:37 AM
Hello there,
before accessing a child transform with GetChild(someNumber), you should always check that someNumber is less than the transform's childCount, otherwise you will get an out of bounds exception (because the child doesn't exist).
Probably the reason why the first planet is moved, but the rest isn't is that Transform star = this.transform.GetChild(i); is valid ( childCount is checked in the for loop), but after moving it you try to access star.GetChild(0); and star.GetChild(0).GetChild(0), which may not exist, so you get an exception. When you get an exception, the execution of that script is stopped at that point.
Instead of a constant number of for loops I highly recommend doing what you are trying to do with recursion. Recursion basically means that you call the same function from itself over and over, but with different parameters, with a different subset of the problem, until some condition is met (usually that the subset is empty or the solution is trivial). Your above code could be rewritten like this:
public void MoveObjectsToListPosition() {
// rewrite of the first loop using a recursive function
for (int i = 0; i < transform.childCount; ++i) {
Transform star = transform.GetChild(i);
star.position = transform.position;
MoveChildrenTo(star, star.position);
}
// or you can just replace all of the above with one more level of recursion
MoveChildrenTo(transform, transform.position);
}
private void MoveChildrenTo(Transform parent, Vector3 parentPosition) {
for (int i = 0; i < parent.childCount; ++i) {
Transform child = parent.GetChild(i);
child.position = parentPosition;
MoveChildrenTo(child, child.position);
}
}
However, I think there is a logic error in the code, because this will move everything to the same position of the transform containing the script. I think what you want to achieve is to move everything relative to their parent, like in a solar system. For that, first move the children, and then the parent. With the above recursion this is easily achieved by first calling the recursion ( MoveChildrenTo()) and only after assigning the position to the parent's ( child.position = parentPosition;) (so swap the 2 lines).
I hope this helps solve your original problem, and also understand programming a bit better! :)
This was exactly what I was trying to do. I don't know why I didn't think of recursion, it seems so obvious now. Thank you very much!
I'm glad it helped! :)
Recursion is difficult to wrap your $$anonymous$$d around, but whenever you have a repeating data structure (such as a tree or graph or linked list), and you want to do similar things to it, you'll probably need recursion.
That said, there are algorithms that seem to be perfect for recursion, but you can unroll them into a loop. The getting the nth element of the Fibonacci sequence is such an example.
Your answer
Follow this Question
Related Questions
Im trying to set a spawned enemy a transform on another script 0 Answers
Preventing A Teleporting GameObject From Passing Through Walls 2 Answers
How do you access the transform of a gameobject and put it in a variable? 3 Answers
How do I trigger a game object to move a desired distance at a desired speed? 1 Answer
Move parent without moving the child 1 Answer