Menu
CoddyTech

Null в Unity

Часть раздела Основы скриптинга в Unity путешествия по Unity на Coddy. Урок 60 из 85.

У объекта Unity есть две половины: объект C#, на который ссылается ваш скрипт, и объект движка за ним. Destroy(obj) удаляет половину движка в конце кадра, но ваша переменная по-прежнему указывает на половину C#, поэтому с точки зрения обычного C# это не null. Unity переопределяет ==, чтобы учесть это: после уничтожения объекта obj == null возвращает true, как и краткая проверка !obj. Это фальшивый null в Unity.

?., ?? и is null не используют этот ==. Они проверяют ссылку C#, которая всё ещё существует, поэтому вызов выполняется, а обращение к уничтоженному объекту вызывает исключение MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it. Эта метка показывает имя лидера гонки, которого могут выбить (уничтожить):

[SerializeField] private Transform leader;

void Update()
{
    // вызывает исключение после уничтожения leader: string shown = leader?.name ?? "nobody";
    string shown = leader != null ? leader.name : "nobody";
    Debug.Log("Leader: " + shown);
}

Для всего, что происходит от UnityEngine.Object (GameObject, компоненты, ваши скрипты), проверяйте с помощью == null, != null или if (obj), а ?. и ?? оставьте для обычных объектов C#, например строк. Также помните, что Destroy ждёт конца кадра: до этого момента объект всё ещё существует, и == null возвращает false.

challenge icon

Задание

Средне

Останови ошибки дрона после уничтожения его цели.

  1. В Update() замени обе строки на if (target != null) — собственную проверку Unity на null.
  2. Внутри него напиши transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);.

Нажми «Играть»: дрон преследует цель, а затем ждёт, и в Console нет ошибок. Затем нажми «Проверить».

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

using UnityEngine;

public class Chaser : MonoBehaviour
{
    [SerializeField] private Transform target;
    [SerializeField] private float speed = 2f;

    void Start()
    {
        Destroy(target.gameObject, 2f);   // цель уничтожается через 2 секунды
    }

    void Update()
    {
        Vector3 goal = target?.position ?? transform.position;
        transform.position = Vector3.MoveTowards(transform.position, goal, speed * Time.deltaTime);
    }
}

Все уроки раздела Основы скриптинга в Unity

Потренируйтесь самостоятельно: Песочница Unity