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… (Unity - Scripting API: Component.GetComponentInChildren)

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 :slight_smile:

actually you may try GetComponentsInChildren(true)

there is a boolean parameter allow you to include inactive objects

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.

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;
		}
	}
}