Menu
CoddyTech

Подписка в OnEnable

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

Уничтоженный слушатель не удаляет себя из события. Событие по-прежнему хранит его метод, и следующий вызов Invoke вызывает этот метод у уничтоженного компонента. Первое использование transform в этом методе вызывает исключение MissingReferenceException, а поскольку исключение прерывает Invoke, пропускаются и следующие слушатели. Поэтому каждому += нужен -=, а для этого в Unity есть пара методов OnEnable и OnDisable:

public class Guard : MonoBehaviour
{
    public Alarm alarm;

    void OnEnable()
    {
        alarm.OnTriggered += RunTo;
    }

    void OnDisable()
    {
        alarm.OnTriggered -= RunTo;
    }

    void RunTo(Vector3 spot)
    {
        transform.LookAt(spot);
    }
}

Unity вызывает OnDisable, когда объект выключается с помощью SetActive(false), когда скрипт отключается и когда объект уничтожается — перед OnDestroy. OnEnable выполняется каждый раз, когда объект снова включается. С этой парой методов охранник слушает событие ровно до тех пор, пока он активен: уничтоженный охранник удаляется из события, охранник, выключенный для кат-сцены, не реагирует на тревогу, а после повторного включения снова начинает слушать.

Две другие комбинации работают неправильно. Если поместить += в Start, а -= — в OnDisable, охранник, которого выключили и снова включили, больше не будет слушать, потому что Start выполняется только один раз. Если поместить += в OnEnable и не добавить -=, при каждом включении RunTo будет добавляться снова, и один сигнал тревоги вызовет его дважды. Удаление метода, который не подписан на событие, ничего не делает, поэтому в OnDisable никогда не нужна проверка перед -=.

challenge icon

Задание

Легко

Пусть каждый житель деревни слушает колокол только пока он активен.

  1. В Villager.cs перенеси bell.OnRing += Hop; из Start() в новый метод void OnEnable() и удали Start().
  2. Добавь void OnDisable() с bell.OnRing -= Hop;. Кнопка «Проверить» выключает и включает Клео, чтобы проверить это.

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

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

using UnityEngine;

public class Villager : MonoBehaviour
{
    public Bell bell;
    public int ringsToLeave = 3;
    public int hops;

    void Start()
    {
        bell.OnRing += Hop;
    }

    void Update()
    {
        // опуститься обратно на землю после прыжка
        Vector3 p = transform.position;
        transform.position = new Vector3(p.x, Mathf.MoveTowards(p.y, 0.5f, 4f * Time.deltaTime), p.z);
    }

    void Hop(int ring)
    {
        hops++;
        transform.position += Vector3.up * 0.8f;
        if (hops == ringsToLeave)
        {
            Debug.Log(name + " goes home");
            Destroy(gameObject);
        }
    }
}

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

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