Menu
CoddyTech

OnEnableで購読する

CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 11/50。

破棄されたリスナーは、それだけではイベントから抜けません。イベントは引き続きそのメソッドを保持し、次の 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);
    }
}

オブジェクトが SetActive(false) でオフにされたとき、スクリプトが無効にされたとき、またオブジェクトが破棄されたとき、Unity は OnDestroy の前に OnDisable を呼び出します。再び有効になるたびに OnEnable が実行されます。この組み合わせにより、ガードは有効な間だけイベントをリッスンします。破棄されたガードはイベントから取り除かれ、カットシーンのためにオフにされたガードはアラームを無視し、再び有効にするとまたリッスンします。

ほかにも、うまくいかない組み合わせが2つあります。Start で += を使い、OnDisable で -= を使うと、Start は一度しか実行されないため、オフにしてから再びオンにしたガードは二度とリッスンしません。OnEnable で += を使い、-= を使わないと、再び有効になるたびに RunTo が追加され、1回のアラームで2回呼び出されます。登録されていないメソッドを削除しても何も起こらないため、OnDisable の -= で確認を行う必要はありません。

challenge icon

チャレンジ

簡単

スペースキーを押すたびに村の鐘が鳴り(Bell.cs は準備済み)、そのイベント OnRing が村人に通知します。村人は鐘が鳴るたびに跳ね、ringsToLeave 回鳴ると家に帰ります。Hop が村人を破棄します。Ana は2回鳴ると家に帰ります。3回目に鳴らすと、Console に MissingReferenceException が表示されます。

村人がアクティブな間だけ鐘を監視するように、Villager.cs を修正してください。

  • 村人が有効になるたびに、鐘のイベントに Hop を登録し、村人が無効化または破棄されるときに登録を解除してください。Hop と Update は変更しないでください。
  • SetActive(false) で無効化された村人は跳ねません。再び有効にすると、鐘が鳴るたびに1回跳ねます。

Play を押し、鐘を4回鳴らして Console を確認し、それから Check を押してください。

自分で試してみよう

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);
        }
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Unityにおけるゲームアーキテクチャのすべてのレッスン