Menu
CoddyTech

Интерфейсы и TryGetComponent

Часть раздела Архитектура игр в Unity путешествия по Unity на Coddy. Урок 7 из 50.

TryGetComponent запрашивает компонент и за один вызов сообщает, найден ли он. Этот метод работает и с интерфейсами, поэтому обычно именно так проверяют, можно ли нанести урон тому, с чем вы столкнулись. Эта мина наносит урон всему вокруг, что реализует 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 объявляет переменную внутри вызова. TryGetComponent возвращает true и заполняет target, если у объекта есть компонент, реализующий IDamageable; в противном случае он возвращает false, а target равен null. Метод проверяет только этот объект, никогда не его родителя или дочерние объекты.

GetComponent по-разному сообщает об отсутствии класса и отсутствии интерфейса. В Editor вызов GetComponent<Rigidbody>() для объекта без Rigidbody возвращает фальшивый null Unity: == null возвращает true, но ?. его не распознаёт, и вызов выдаёт MissingComponentException. У интерфейса фальшивого null нет: GetComponent<IDamageable>() возвращает настоящий C# null, поэтому с ним работают и == null, и ?.. TryGetComponent позволяет избежать этой проверки в обоих случаях и ничего не выделяет в Editor, если компонент отсутствует.

challenge icon

Задание

Легко

Лазерная башня поворачивается с помощью стрелок влево и вправо, а пробел вызывает Fire() в Laser.cs. Напиши Fire. Выполни лучевой запрос от башни в направлении её передней оси длиной range единиц (в Inspector задано 10), затем:

  • Если луч попал во что-то, у чего есть IDamageable, вызови для него TakeDamage(damage) и выведи в журнал Hit и имя объекта, например Hit Robot.
  • Если у объекта нет IDamageable, но есть Rigidbody, оттолкни его с помощью AddForce(transform.forward * push, ForceMode.Impulse) и выведи в журнал Pushed и его имя.
  • Во всех остальных случаях выведи в журнал Blocked by и имя объекта, например Blocked by Pillar. Если луч ни во что не попал, выведи Missed.

Используй TryGetComponent для обеих проверок. IDamageable.cs, Robot.cs и Balloon.cs уже готовы. Нажми Play и стреляй во всех направлениях, затем нажми Check.

Попробуйте сами

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()
    {
        // Пустите луч вперёд на расстояние range единиц и обработайте то, во что он попадёт
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Архитектура игр в Unity