Unity GetComponent Presentation

Unity – Mastering GetComponent and its Derivatives

In Unity, developers often find themselves relying heavily on `GetComponent`.
This function allows you to retrieve a component attached to your GameObject. In this comprehensive guide, we explore various aspects of `GetComponent` and provide valuable tips and tricks.

Table of Contents

Basic Usage

Unity GetComponent

using UnityEngine;

public class MonoBehaviourComponent : MonoBehaviour
{
    private void Action()
    {
        // Using GetComponent right away, as MonoBehaviour extends Component

        // Base Method
        var boxCollider2d = GetComponent<BoxCollider2D>();

        // With type as a parameter
        var box2 = GetComponent(typeof(BoxCollider2D)) as BoxCollider2D;
    }
}

What is a Component?

A component in Unity is a C# script inheriting from `UnityEngine.Component`, attached to a GameObject to perform various tasks such as rendering, gameplay, or collision handling… All components have access to the component “search” functions provided by `UnityEngine.Component`.

Unity inspector components Unity Inspector with 3 components

TryGetComponent Method

`TryGetComponent` is used in a scenario where you are unsure if the component is attached to your GameObject. This function returns `true` if the component is found.

private void Handle()
{
  if (TryGetComponent<BoxCollider2D>(out BoxCollider2D boxCollider2D))
  {
    boxCollider2D.isTrigger = true;
  }
}

GetComponent for Interfaces

You can also retrieve components that implement an interface using `GetComponent`. For example, you can get a component that implements the `IPointerDownHandler` interface.

using UnityEngine;
using UnityEngine.EventSystems;

public class MonoBehaviourComponent : MonoBehaviour
{
  public GameObject referenceGameObject;

  private void Awake()
  {
    var pointer = referenceGameObject.GetComponent<IPointerDownHandler>();
  }
}

GetComponents

The `GetComponents` function allows you to retrieve all components of a same type to a GameObject.

private void Action()
{
  var boxCollider2Ds = GetComponents<BoxCollider2D>();

  foreach (var boxCollider in boxCollider2Ds)
  {
    boxCollider.isTrigger = true;
  }
}

Note: This function returns an array of elements of the specified type.

This function can also be used by passing a list as a parameter to avoid having to recreate a list on each call:

private List<BoxCollider2D> _boxColliders = new List<BoxCollider2D>();

private void Update()
{
	GetComponents(_boxColliders);

	foreach(var boxCollider in _boxColliders)
	{
		// do some actions
	}
}

GetComponentInChildren

Unity GetComponentInChildren

`GetComponentInChildren` retrieves a component of a specific type from the GameObject itself or from a child GameObject.

private void InChildren()
{
  // Find first Image in itself or its children (work only if gameObject is active) 
  var image = GetComponentInChildren<Image>();
  image.color = Color.red;

  // Find first Image in itself or its children
  var imageDisabled = GetComponentInChildren<Image>(true);
}

GetComponentsInChildren

Discover how to retrieve all components of a specific type from the GameObject itself and its childrens using `GetComponentsInChildren`.

private void InChildrens()
{
  // Find all Images in itself & its children (work only if gameObject is active) 
  var images = GetComponentsInChildren<Image>();

  foreach (var image in images)
  {
    image.sprite = null;
  }

  // Find all Images in itself & its children 
  var disabledImages = GetComponentsInChildren<Image>(true);
}

Note: This function can also be used by passing a list as a parameter to avoid having to recreate a list on each call.

GetComponentInParent

Unity GetComponentInParent

`GetComponentInParent` retrieve a component of a specific type from the GameObject itself or from a parent.

private void InParent()
{
  // Find the first Image in itself or its parents (work only if gameObject is active) 
  var image = GetComponentInParent<Image>();
  image.color = Color.red;

  // Since Unity 2020, find the first Image in itself or its parents 
  var imageDisabled = GetComponentInParent<Image>(true);
}

GetComponentsInParent

Explore `GetComponentsInParent` to retrieve all components of a specific type in the GameObject itself and its parents.

private void InParents()
{
  // Find all Images in itself & its parents (work only if gameObject is active) 
  var images = GetComponentsInParent<Image>();

  foreach (var image in images)
  {
    image.sprite = null;
  }

  // Find all Images in itself & its parents
  var disabledImages = GetComponentsInParent<Image>(true);
}

Note: To avoid recreating a list on each call, this function can have a list as parameter.

A little tip, to avoid searching on itself, you can call the method directly on the parent:

var imagesWithoutSelf = transform.parent.GetComponentsInParent<Image>();

GetComponent by Name (Avoid)

Finding a component with the name of the gameObject is not a good approach. The function used to do this is `GameObject.Find`, but it’s not very efficient. For better performance you can use other methods such as direct references or tracking components in a manager.

private void FindByName()
{
  // Avoid this call...
  var boxCollider2d = GameObject.Find("MyGameObjectName").GetComponent<BoxCollider2D>();
}

Component by Reference

Instead of using `GetComponent`, consider creating a serializable property to reference your component directly.

using UnityEngine;

public class MonoBehaviourComponent : MonoBehaviour
{
    public BoxCollider2D boxCollider2D;

    // or, if you prefer a private field
    [SerializeField]
    private BoxCollider2D _boxCollider2D;
}

Reference Component with Static List

Utilize the `OnEnable` and `OnDisable` methods to track components of the same type by adding and removing them from a static list.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MonoBehaviourComponent : MonoBehaviour
{
    public BoxCollider2D boxCollider2D;
    public string code;

    public static List<MonoBehaviourComponent> ListComponents { get; private set; } = new List<MonoBehaviourComponent>();

    private void OnEnable() => ListComponents.Add(this);
    private void OnDisable() => ListComponents.Remove(this);
}

Now we use the identifier (code) instead of the name to call the component, e.g. using LINQ:

using System.LINQ;

// Expection not handle in this code
var boxCollider2d = MonoBehaviourComponent.ListComponents.Single(x => x.code == "myCode").boxCollider2D;

Reference Component with Manager

Create a manager to handle your MonoBehaviour components. The manager can instantiate and destroy components, providing a centralized way to manage your components.

I love using managers because they allow me to develop my code very easily. You can start from this base and then add a pool system, events …

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ComponentManager : MonoBehaviour
{
    // it's a model, can be a prefab
    public MonoBehaviourComponent monoBehaviourComponent;

    public List<MonoBehaviourComponent> components = new List<MonoBehaviourComponent>();

    public static ComponentManager Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
    }

    public void InvokeComponent(string code)
    {
        var instance = Instantiate(monoBehaviourComponent);
        instance.code = code;

        components.Add(instance);
    }

    public void DestroyComponent(MonoBehaviourComponent component)
    {
        if (components.Contains(component))
        {
            components.Remove(component);
        }

        Destroy(component.gameObject);
    }

    public MonoBehaviourComponent GetComponentByCode(string code)
    {
        return components.SingleOrDefault(x => x.code == code);
    }
}

Using our old example, we would make a call like this:

var boxCollider2d = ComponentManager.Instance.GetComponentByCode("myCode").boxCollider2D;

GetComponent Good Practise (Avoid NullReferenceException)

It is recommended in a Monobehaviour to define your `GetComponent` calls in the `Awake` method and then use them during or after the `Start` method to avoid `NullReferenceException`. This pattern ensures that `Awake` is only used for defining components or Singletons, and `Start` is used for configuration.

[SerializeField]
private BoxCollider2D _boxCollider2D;

private void Awake()
{
  _boxCollider2D = GetComponent<BoxCollider2D>();
}

private void Start()
{
  _boxCollider2D.isTrigger = true;
}

Avoid GetComponent in Update

Cache your `GetComponent` calls in a field or avoid calling them every frame. Remember that, by default, no caching is applied to these functions. If you call, for example, `GetComponentInParent` in an `Update`, it will search through all parents every frame, potentially harming performance.

[SerializeField]
private BoxCollider2D _boxCollider2D;

private List<ContactPoint2D> _contactPoints = new List<ContactPoint2D>();

private void Awake()
{
  _boxCollider2D = GetComponent<BoxCollider2D>();
}

private void FixedUpdate()
{
  if (_boxCollider2D.GetContacts(_contactPoints) > 0)
  {
    // Perform actions with contact
  }
}

Conclusion

I hope this tutorial has provided valuable insights into working with components in Unity. Whether you are a beginner or an experienced developer, mastering the usage of `GetComponent` and related methods is crucial for efficient Unity development.

Thank you for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *