Menu
CoddyTech

Null в Unity

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

У объекта Unity есть две половины: объект C#, на который ссылается ваш скрипт, и лежащий за ним объект движка. Destroy(obj) удаляет половину движка в конце кадра, но ваша переменная по-прежнему указывает на половину C#, поэтому с точки зрения обычного C# она не равна null. Unity переопределяет ==, чтобы учесть это: после уничтожения объекта выражение obj == null истинно, как и короткая проверка !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 (GameObjects, компоненты, ваши скрипты), используйте проверки == null, != null или if (obj), а ?. и ?? оставьте для обычных объектов C#, например строк. Также помните, что Destroy ждёт конца кадра: до этого момента объект всё ещё существует, а == null возвращает false.

challenge icon

Задание

Средне

Дрон преследует цель, и цель уничтожается через 2 секунды после начала игры. После этого в консоли появляются ошибки MissingReferenceException, потому что target?.position не замечает, что цель исчезла.

Исправь Update(), используя собственную проверку null в Unity: пока цель существует, дрон летит к ней со скоростью speed; после её уничтожения дрон остаётся на месте, без ошибок.

Нажми Play и следи за консолью, исправь скрипт, затем нажми Check.

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

using UnityEngine;

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

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

    void Update()
    {
        Vector3 goal = target?.position ?? transform.position;
        transform.position = Vector3.MoveTowards(transform.position, goal, speed * Time.deltaTime);
    }
}
quiz iconПроверьте себя

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

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