Menu
CoddyTech

Inscreva-se em OnEnable

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

Um ouvinte que é destruído não deixa o evento por conta própria. O evento ainda mantém seu método, e o próximo Invoke o chama no componente destruído. O primeiro uso de transform nesse método lança uma MissingReferenceException e, como uma exceção encerra o Invoke, os ouvintes que vêm depois também são ignorados. Portanto, cada += precisa de um -=, e o par de métodos do Unity para isso é OnEnable e 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);
    }
}

O Unity chama OnDisable quando o objeto é desativado com SetActive(false), quando o script é desabilitado e quando o objeto é destruído, antes de OnDestroy. OnEnable é executado toda vez que ele é ativado novamente. Com esse par, um guarda ouve exatamente enquanto está ativo: um guarda destruído deixa de fazer parte do evento, um guarda desativado durante uma cena ignora o alarme e, quando é ativado novamente, volta a ouvir.

Dois outros pareamentos dão errado. Com += em Start e -= em OnDisable, um guarda desativado e ativado novamente nunca mais ouve, porque Start é executado apenas uma vez. Com += em OnEnable e sem -=, cada retorno adiciona RunTo novamente, e um alarme o chama duas vezes. Remover um método que não está inscrito não faz nada, então nunca é necessário verificar antes de usar -= em OnDisable.

challenge icon

Desafio

Fácil

Faça com que cada aldeão ouça o sino somente enquanto estiver ativo.

  1. Em Villager.cs, mova bell.OnRing += Hop; de Start() para um novo void OnEnable() e exclua Start().
  2. Adicione void OnDisable() com bell.OnRing -= Hop;. O botão “Verificar” desativa e ativa Cleo para testar isso.

Pressione “Jogar” e toque o sino quatro vezes: Ana vai para casa depois do toque 2, e nenhum erro aparece. Em seguida, pressione “Verificar”.

Experimente você mesmo

using UnityEngine;

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

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

    void Update()
    {
        // volte ao chão depois de um salto
        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);
        }
    }
}

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

Pratique por conta própria: Playground de Unity