Menu
CoddyTech

Interfaces e TryGetComponent

Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 8 de 64.

TryGetComponent procura um componente e informa se encontrou um, tudo em uma única chamada. Também funciona com interfaces, o que faz dele a maneira habitual de verificar se aquilo em que você bateu pode receber dano. Esta mina causa dano a tudo ao redor que seja 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 declara a variável dentro da chamada. TryGetComponent retorna true e preenche target quando o objeto tem um componente que implementa IDamageable; caso contrário, retorna false e target é null. Ele verifica apenas aquele objeto, nunca o pai nem os filhos.

GetComponent trata um componente ausente de classe e um componente ausente de interface de maneiras diferentes. No Editor, GetComponent<Rigidbody>() em um objeto sem Rigidbody retorna o null falso do Unity: == null é true, mas ?. não o detecta e a chamada lança MissingComponentException. Uma interface não tem null falso: GetComponent<IDamageable>() retorna um null real do C#, então == null e ?. funcionam com ele. TryGetComponent evita essa questão nos dois casos e não aloca nada no Editor quando o componente está ausente.

challenge icon

Desafio

Fácil

Escreva Fire() em Laser: um raio, quatro resultados.

  1. Dispare Physics.Raycast da torre na direção de transform.forward, com o comprimento de range. Se não acertar nada, registre Missed.
  2. Se hit.collider.TryGetComponent(out IDamageable target), chame TakeDamage(damage) e registre "Hit " + hit.collider.name.
  3. Caso contrário, se tiver um Rigidbody, aplique AddForce(transform.forward * push, ForceMode.Impulse) e registre "Pushed " junto com o nome; caso contrário, "Blocked by " junto com o nome.

Pressione “Jogar”, vire-se e atire em todas as direções. Depois, “Verificar”.

Experimente você mesmo

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()
    {
        // Emita um raio para a frente, com comprimento de range unidades, e lide com o que ele atingir
    }
}

Todas as lições de Arquitetura de Jogos no Unity

Pratique por conta própria: Playground de Unity