Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by darbotron · Oct 13, 2013 at 08:44 PM · gameobjectcomponentinactivegetcomponentinchildren

Possible to make GameObject.GetComponentInChildren() check inactive objects?

I've recently started needing to have multiple game states within my game, and decided to set object hierarchies within the scene inactive / active to manage this state.

I was initially very confused by the fact that GameObject.GetComponentInChildren() doesn't work for components on inactive GameObjects.

Though it is mentioned in the online documentation it's far from obvious - this is the sort of behaviour that should be printed in massive bold letters or under a "please note" heading... (http://docs.unity3d.com/Documentation/ScriptReference/Component.GetComponentInChildren.html)

After a bit of googling / poking about in forums etc. I couldn't find any "standard" way (i.e. out of the box unity function) to do it...

...but I did find enough info to write my own code to do it; and since I had not found any conclusive answers I decided to post a question and then answer it to help anyone else who might be stuck with the same issue :)

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
5
Best Answer

Answer by darbotron · Oct 13, 2013 at 08:55 PM

So whilst GetComponentInChildren() doesn't check the components of inactive GameObjects, it turns out that GetComponent() does check the components of an inactive obejct.

The obvious solution to my problem was to write code to traverse a GameObject hierarchy by hand and call GetComponent() manually on each GameObject.

Here's the code:

 ///////////////////////////////////////////////////////////////
 /// <summary>
 /// Game object tools.
 /// </summary>
 ///////////////////////////////////////////////////////////////
 static public class GameObjectTools
 {
     ///////////////////////////////////////////////////////////
     // Essentially a reimplementation of 
     // GameObject.GetComponentInChildren< T >()
     // Major difference is that this DOES NOT skip deactivated 
     // game objects
     ///////////////////////////////////////////////////////////
     static public TType GetComponentInChildren< TType  >( GameObject objRoot ) where TType : Component
     {
         // if we don't find the component in this object 
             // recursively iterate children until we do
         TType tRetComponent = objRoot.GetComponent< TType >();                
         
         if( null == tRetComponent )
         {
             // transform is what makes the hierarchy of GameObjects, so 
                     // need to access it to iterate children
             Transform     trnsRoot        = objRoot.transform;
             int         iNumChildren     = trnsRoot.childCount;
             
             // could have used foreach(), but it causes GC churn
             for( int iChild = 0; iChild < iNumChildren; ++iChild )
             {
                 // recursive call to this function for each child
                 // break out of the loop and return as soon as we find 
                 // a component of the specified type
                 tRetComponent = GetComponentInChildren< TType >( trnsRoot.GetChild( iChild ).gameObject );
                    if( null != tRetComponent )
                 {
                     break;
                 }
             }
         }
         
         return tRetComponent;
     }
 }

I've not bothered to do an equivalent for GetComponentsInChildren() but it should be a simple enough extension of the code above.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image darbotron · Jan 27, 2015 at 03:51 PM 0
Share

I'd just like to add another comment here - people have upvoted the below comment, which is fine.

To be 100% clear GetComponentsInChildren() returns an array which is allocated with new and therefore will incur GC cost.

If what you want to do is just get a single component in children then the code above is still a better bet I$$anonymous$$O - certainly I use it myself in preference to GetComponentsInChildren() when appropriate.

avatar image JohnTube · Mar 15, 2015 at 03:46 AM 0
Share

That's exactly what I needed ! Thank you for the quality of the code, it's so $$anonymous$$ono/Unity friendly. I've made an extension method out of it.

avatar image
20

Answer by NickWu · Mar 28, 2014 at 09:31 AM

actually you may try GetComponentsInChildren(true) https://docs.unity3d.com/Documentation/ScriptReference/Component.GetComponentsInChildren.html there is a boolean parameter allow you to include inactive objects

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image darbotron · Apr 01, 2014 at 08:15 AM 0
Share

I'm not sure this bool has always been there, if it has I missed it! the code I posted also works for this BTW :)

avatar image knifesk · May 27, 2014 at 04:20 PM 2
Share

notice that the single component method doesn't have the parameter... only the components[] version... the one that returns an array... the one with an S... this one: GetComponentsInChildren

avatar image darbotron · Jul 28, 2014 at 10:35 AM 0
Share

I chose my solution as the answer because this optional flag is only available on GetComponentsInchildren() which returns an array and I wanted a solution that returned just the first component.

Also my solution doesn't cause any allocation AFAI$$anonymous$$ so no associated GC hit, which GetComponentsInchildren() definitely does have...

avatar image
0

Answer by canis · Oct 04, 2016 at 06:37 PM

I know it's the old post, but after I saw it, I run some test for myself. and here is my version,

 /// <summary>Get Component within child transform (extension)</summary>
         /// <typeparam name="T">Component class</typeparam>
         /// <param name="component">this</param>
         /// <param name="depth">searching depth, stop search when reching Zero.</param>
         /// <param name="includeInactive">include inactive gameobject.</param>
         /// <param name="includeSelf">include the caller itself.</param>
         /// <returns>Return first found component</returns>
         /// <remarks>The performance are much slower then the original, avg: 4x ~ 20x depend on how many level needed to drill down.</remarks>
         public static T GetComponentInChildren<T>(this Component component, int depth = 1, bool includeInactive = false, bool includeSelf = true) where T : Component
         {
             T rst = null;
             if (includeSelf)
                 rst = component.GetComponent<T>();
             else if(depth < 0)
                 Debug.LogError("Syntax Error: GetComponentInChildren<" + typeof(T).Name + "> You searching for nothing.", component.gameObject);
             if (depth > 0 && rst == null)
             {
                 depth--;
                 foreach (Transform child in component.transform)
                 {
                     if (includeInactive && !child.gameObject.activeSelf)
                         continue;
                     rst = child.GetComponentInChildren<T>(depth, includeInactive, true);
                     if (rst != null)
                         return rst;
                 }
             }
             return rst;
         }

funny thing is it's much slower then the original GetComponentInChildren() welcome anyone to improve this.

and here is the test code that I'm using to test the performance.

 using UnityEngine;
 using Kit.Extend;
 
 public class CaseTest : MonoBehaviour
 {
     [Range(0, 1)]
     public int m_TestCase = 0;
     public int m_Depth = 10;
     public int m_Cycle = 10;
 
     void OnEnable()
     {
         System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
         clock.Start();
 
         Collider rst = null;
         switch (m_TestCase)
         {
             case 0:
                 for (int i = 0; i < m_Cycle; i++)
                     rst = GetComponentInChildren<Collider>(true);
                 break;
 
             case 1:
                 for (int i = 0; i < m_Cycle; i++)
                     rst = this.GetComponentInChildren<Collider>(m_Depth, true, true);
                 break;
         }
         clock.Stop();
 
         if (rst == null)
         {
             Debug.LogWarningFormat("{2} {0}, Time : {1}",
                 (rst == null ? "-NONE-" : "Found"),
                 clock.ElapsedTicks,
                 (m_TestCase == 0 ? "Original" : "extension"));
         }
         else
         {
             Debug.LogWarning(string.Format("{2} {0}, Time : {1}",
                 (rst == null ? "-NONE-" : "Found"),
                 clock.ElapsedTicks,
                 (m_TestCase == 0 ? "Original" : "extension")), rst.gameObject);
         }
 
         clock.Reset();
     }
 
     [ContextMenu("Generate levels with collider")]
     public void Generate()
     {
         int x = 1000;
         Transform level = transform;
         while(x-- > 0)
         {
             Transform next = new GameObject("have collider in " + x.ToString()).transform;
             next.SetParent(level);
             level = next;
         }
 
         level.GetOrAddComponent<BoxCollider>();
     }
 
     [ContextMenu("Generate some empty levels")]
     public void GenerateEmpty()
     {
         int x = Random.Range(10, 1000);
         Transform level = transform;
         while (x-- > 0)
         {
             Transform next = new GameObject("Nothing").transform;
             next.SetParent(level);
             level = next;
         }
     }
 }
 


Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image darbotron · Oct 04, 2016 at 07:38 PM 0
Share

Hey. Thanks for posting. It's always nice to see someone with enough curiosity to fiddle with stuff :)

It's not surprising that your function (and, I assume, the original one I posted) are slower than the stock Unity implementation - we have to use their API to access the objects whereas their code is inside the API; in addition to the recursive function calls it's calling at least one Unity API function on each iteration of the recursion :)

I wouldn't have written it as a recursive function if speed were an issue for my use case - generally (I$$anonymous$$O) you should only be calling functions that traverse the Transform graph (like GetComponentInChildren()) during initialisation code or you're asking for trouble...

I'd be interested to hear how much slower it is as well - in general I'd want to see more like 1000 to 10000 iterations of the loops for meaningful profiling results.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

19 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Can I move a component from one GameObject to another in script? 1 Answer

How to mimic Unity's Components based System 1 Answer

How to Check if a component Exists on a Gameobject. 3 Answers

Storing component of instance in an array 2 Answers

How do you place an image on an object so that the object size is based on pixels per unit and image size? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges