- Home /
Use GetComponentsInChildren but don't access grand children
I have a script and it uses the GetComponentsInChildren function on a game object but when the function is executed, it returns all the children including the grandchildren.
How do I make the GetComponentsInChildren function only access the first children in yellow and not access the grandchildren?
Note that Unity's GetComponentsInChildren does also return components on the given object, not only on children. The name is actually badly choosen. Something like GetComponentRecursive probably would have been better ^^.
Answer by yummy81 · Feb 18, 2018 at 07:11 PM
I wrote that script for you on the fly. Attach it to your "Parent" gameobject and check whether it works as you want. I created the "GetComponentsInDirectChildren" extension method which returns the list of desired components in direct children (in gameobjects you marked in yellow). Additionally, I created "GetComponentsRecursive" extension method which returns the list of desired components in direct children and the parent. Here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Raja : MonoBehaviour
{
private void Awake()
{
var children = gameObject.GetComponentsInDirectChildren<Transform>();
foreach (var child in children)
{
Debug.Log(child.name);
}
}
}
public static class Extensions
{
public static List<T> GetComponentsRecursive<T>(this GameObject gameObject) where T : Component
{
int length = gameObject.transform.childCount;
List<T> components = new List<T>(length + 1);
T comp = gameObject.transform.GetComponent<T>();
if (comp != null) components.Add(comp);
for (int i = 0; i < length; i++)
{
comp = gameObject.transform.GetChild(i).GetComponent<T>();
if (comp != null) components.Add(comp);
}
return components;
}
public static List<T> GetComponentsInDirectChildren<T>(this GameObject gameObject) where T : Component
{
int length = gameObject.transform.childCount;
List<T> components = new List<T>(length);
for (int i = 0; i < length; i++)
{
T comp = gameObject.transform.GetChild(i).GetComponent<T>();
if (comp != null) components.Add(comp);
}
return components;
}
}
You may want to rename the method to something like GetComponentsInDirectChildren ^^. If you get back to that project in 3 years or if multiple people work on the same project you / they wouldn't have any idea what "GetComponentsInChildren2" does ^^. Also since you are creating a List anyways i would return the list directly. There's no need to return an array if you already have a list. In many cases a list would be more useful and it actually prevents the additional array creation. Also you may want to set the list capacity to "length". This will avoid unnecessary resizing if there are many childs. There is a List constructor that takes an int value for the initial capacity.
Also such helpers probably should be extension methods ^^. Also another version that takes a list as parameter might be a good idea especially for mobile (a GC friendly variant).
Thank you @Bunny83 for your remarks. I modified my code. The reason why I initially chose to convert list into array was that I wanted my method to resemble the Unity's GetComponentsInChildren - the Unity's one returns array. Now, both of them return list. You are also right that the Unity's GetComponentsInChildren also returns the component on the parent object, but OP wanted only those marked in yellow, so, while being aware of that, I created my method to suit his needs. There's also one more difference - my methods do not care whether component is on active or inactive gameobject. And, of course, I know that these na$$anonymous$$g things are terrible :)
Answer by Szkeptik · May 13, 2021 at 01:31 PM
With System.Linq you can do:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class MyClass : MonoBehaviour{
Component[] directChildren;
void Start{
directChildren = (from directChild in GameObject.Find("Parent").transform.
GetComponentsInChildren<Component>()
where directChild.transform.name == "Child"
select directChild).ToArray();
}
}
Or if you don't want to rely on the naming:
public GameObject parentGO; // drag into field in editor
Component[] directChildren = (from directChild in parentGO.
GetComponentsInChildren<Component>()
where directChild.transform.parent == parentGO.transform
select directChild).ToArray();
Or if you don't want to use Linq:
List<Component> directChildren = new List<Component>();
foreach(Transform go in parentGO.transform){ // This will only find direct children
Component c = go.gameObject.GetComponent<Component>();
directChildren.Add(c);
}
Your answer
Follow this Question
Related Questions
Initialising List array for use in a custom Editor 1 Answer
Confused about custom GameObjects,Custom GameObject confusion 0 Answers
myObjetc..GetType().GetCustomAttributes(typeof(RequireComponent) not working correctly 1 Answer
Get callback when assets loading or deserialization finished? 1 Answer
Build problem 1 Answer