Menu
CoddyTech

Interfaces and TryGetComponent

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 8 of 64.

TryGetComponent asks for a component and tells you whether it found one, in one call. It works with interfaces too, which makes it the usual way to ask whatever you hit whether it can be hurt. This mine hurts everything around it that is IDamageable:

public class Mine : MonoBehaviour
{
    public float radius = 3f;
    public int damage = 5;

    void OnTriggerEnter(Collider other)
    {
        foreach (Collider c in Physics.OverlapSphere(transform.position, radius))
        {
            if (c.TryGetComponent(out IDamageable target))
            {
                target.TakeDamage(damage);
            }
        }
        Destroy(gameObject);
    }
}

out IDamageable target declares the variable inside the call. TryGetComponent returns true and fills target when the object has a component that implements IDamageable; otherwise it returns false and target is null. It looks only at that one object, never its parent or children.

GetComponent reports a missing class and a missing interface differently. In the Editor, GetComponent<Rigidbody>() on an object with no Rigidbody returns Unity's fake null: == null is true, but ?. does not see it and the call throws MissingComponentException. An interface has no fake null: GetComponent<IDamageable>() returns a real C# null, so == null and ?. both work on it. TryGetComponent avoids the question for both, and it allocates nothing in the Editor when the component is missing.

challenge icon

Challenge

Easy

Write Fire() in Laser: one ray, four outcomes.

  1. Cast Physics.Raycast from the tower along transform.forward, range long. On a miss, log Missed.
  2. If hit.collider.TryGetComponent(out IDamageable target), call TakeDamage(damage) and log "Hit " + hit.collider.name.
  3. Else, if it has a Rigidbody, AddForce(transform.forward * push, ForceMode.Impulse) and log "Pushed " plus the name; else "Blocked by " plus the name.

Press Play, turn and fire every way. Then Check.

Try it yourself

using UnityEngine;
using UnityEngine.InputSystem;

public class Laser : MonoBehaviour
{
    public float range = 10f;
    public int damage = 1;
    public float push = 5f;
    public float turnSpeed = 90f;

    private InputAction moveAction;

    void Start()
    {
        moveAction = InputSystem.actions.FindAction("Move");
    }

    void Update()
    {
        float turn = moveAction.ReadValue<Vector2>().x;
        transform.Rotate(0f, turn * turnSpeed * Time.deltaTime, 0f);
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            Fire();
        }
    }

    void Fire()
    {
        // Cast a ray forward, range units long, and deal with what it hits
    }
}

All lessons in Game Architecture in Unity

Practice on your own: Unity playground