- Home /
The question is answered, right answer was accepted
GetComponentInChildren Returning a Component in Parent
I'm having a problem where GetComponentInChild actually is finding the component in the parent.
My hierarchy is more/less like so (and the script I'm testing this with is below): Parent (with UISprite) -child 1 (no UISprite component) -child 2 (with UISprite)
void Awake ()
{
uiSprite = gameObject.GetComponentInChildren<UISprite>();
uiSprite.name = "should be child";
}
I am wondering if I am using this method incorrectly, or if this is the intended behavior? Any advice is appreciated
GetComponentInChildren returns one component, and it can detect the component of the parent as well as the child object. You can use "GetComponentsInChildren" to get an array and check if the component is attached to the parent object.
In addition scripting reference has already mentioned this.
GetComponent Returns the component of Type type if the game object has one attached, null if it doesn't. You can access both builtin components or scripts with this function.
GetComponentInChildren Returns the component of Type type in the GameObject or any of its children using depth first search.
GetComponents Returns all components of Type type in the GameObject.
GetComponentsInChildren Returns all components of Type type in the GameObject or any of its children.
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.html
I am not sure, I usually have exact isuue to you, so to make sure usually I type strictly like this:
THIS.gameObject.blablabla ins$$anonymous$$d of gameobject.blabla
sometimes that made different result, I make assumption that probably gameObject pointed to top hierarchy first,but sometimes fine as expected.
@ koray1396: you and pako are correct, using an array is a good solution for this, thank you both for the suggestions. I'm dissapointed in myself for not looking at the script reference but I think I just thought, "well if it says in child, why would it look in the parent?" But I should always check it anyway.
Answer by pako · Mar 29, 2014 at 10:45 AM
Since GetComponentInChildren() searches the parent as well, and returns only the first component it finds, it will return the parent's component, if the parent has a UISprite attached. Therefore, the solution is to use GetComponentsInChildren() to get an array of all UISprite components found in parent and children, and then iterate through the array to find the one you want:
void Awake ()
{
UISprite[] uiSprites = gameObject.GetComponentsInChildren<UISprite>();
foreach(UISprite uiSprite in uiSprites)
{
if(uiSprite.gameObject.transform.parent != null)
{
uiSprite.gameObject.name = "should be child"; //this gameObject is a child, because its transform.parent is not null
}
}
}
@ pako: you and koray1396 are correct, using an array is a good solution for this, thank you both for the suggestions. I'm dissapointed in myself for not looking at the script reference but I think I just thought, "well if it says in child, why would it look in the parent?" But I should always check it anyway.
@boddole I'm not sure why unity wanted GetComponentInChild() to start searching from it self(the gameObject that calls it), ins$$anonymous$$d of starting from the child. Should this be reported as a bug?
Same sentiment. Why would unity want to do this in any way?
Answer by andrealaiena · Jul 14, 2014 at 11:50 AM
Simpler way I found:
void Awake ()
{
uiSprite = gameObject.GetComponentsInChildren<UISprite>()[1]; //it "jumps" the parent and gives you the child component :D
uiSprite.name = "should be child";
}
This would be a good way to directly access a child, only in the case that you know that a child is available and that the parent has the same component attached. Otherwise we'd get a null reference exception. It is applicable in this specific situation, but I think the statement "should be child" requires a more general answer. i.e. "should be child" is not true if there's no parent, and "should be child" is not true if the parent does not have the same component attached.
This is not a safe solution and I would recomment against this solution for the following reasons.
It will fail and produce unpredictable results if and when the parent does not have a compontnent of type .
It will throw an exception if there currently are no children with type .
In general, code that makes assumptions about state is bad and difficult to debug because the assumptions might not be obvious in the future or to other developers.
Ins$$anonymous$$d, make an extension method or explicitly asset the assumptions you're making:
Assert.isNotNull(gameObject.GetComponent<UISprite>()) // parent has a UI Sprite
Assert.IsTrue(gameObject.GetComponentsInChildren<UISprite>().Count > 1); // There are more than 1 objects returned from the call to GetComponents.
Seeing that a post is still "alive" after 4 years shows how valuable this forum is.
So, after @Cameron860 gave some important points in his comments, I revisited this post, and noticed that @DottoProto 's answer produces a null reference as is: GetComponentsInChildren<UISprite>()[1]
returns the first child, which does NOT have a UISprite
component per the OP's description:
Parent (with UISprite) -child 1 (no UISprite component) -child 2 (with UISprite)
So, even in this particular case, this answer is wrong!
Answer by Bomanden · Sep 26, 2016 at 10:07 AM
was just searching for the same .
with linq - if you dont want to include the parentsComponent.
using System.Linq;
var childrenList = this.GetComponentsInChildren<RectTransform>(true).Where(x => x.gameObject.transform.parent != transform.parent).ToList();
or even better , use neuecc's exelente linq to GameObject.
https://github.com/neuecc/LINQ-to-GameObject-for-Unity
using Unity.Linq; //https://github.com/neuecc/LINQ-to-GameObject-for-Unity
var Markers = GameObject.Find("Container").Children().OfComponent<Transform>().ToList();
Answer by ben-rasooli · Feb 02, 2016 at 09:52 AM
You might also consider this:
uiSprite = transform.Find("Child Name").GetComponent<UISprite>();