Help us understand the problem. What is going on with this article?

UnityでStartCoroutineを実行した際のNullReferenceException対策

UnityでStartCoroutineメソッドを実行した際に、なぜかNullReferenceExceptionのエラーが発生して2時間ほどハマったので、その解決策をメモしておきます。

結論から言うと、Update()メソッド以外のメソッドからコルーチン処理を実行する(StartCoroutineメソッドを実行する)場合は、そのコルーチン処理を呼び出すためのオブジェクトをnewで直接生成してはならないようです。

StartCoroutineの使い方について解説している他の参考サイトなどでは、Update()メソッド内からStartCoroutineを実行している事例しか見当たらなかったため、今回のように他のメソッドから実行したい場合はどうすればよいのか悩みました。

まず、Updateメソッド内からコルーチン処理を呼び出す事例を載せておきます。

EventManager.cs
public class EventManager : MonoBehaviour
{
    void Update()
    {
        //Updateメソッド内からコルーチン呼び出し(この場合は正常に実行できる)
        StartCoroutine("Event");
    }

    //コルーチン関数"Event"を定義
    IEnumerator Event()
    {
        Debug.Log("あいうえお");

        //マウス左クリックを待つ処理
        yield return new WaitUntil(() => Input.GetMouseButtonDown(0));

        Debug.Log("かきくけこ");
    }
}

出力結果を確認すると、正常に実行できていました。

次に、エラーが発生した事例を載せておきます。

EventManager.cs
public class EventManager : MonoBehaviour
{
    public static void CallEvent(string eventName)
    {
        //EventManager のオブジェクトをnewで生成
        EventManager eventManager = new EventManager();
        //コルーチン呼び出し(この場合はエラーが発生する)
        eventManager.StartCoroutine("Event");
    }

    //コルーチン関数"Event"を定義
    IEnumerator Event()
    {
        Debug.Log("あいうえお");

        //マウス左クリックを待つ処理
        yield return new WaitUntil(() => Input.GetMouseButtonDown(0));

        Debug.Log("かきくけこ");
    }
}

今回は、他のクラスからCallEventメソッドを呼び出して"Event"というコルーチン処理を実行しようとしています。しかし、実行結果はNullReferenceExceptionが発生してしまいました。
MonoBehaviour(及びそれを継承したEventManagerクラス)をnewで直接生成しているのがエラーの原因です。

ではどうするのかと言うと、newではなくAddComponentメソッドを使ってオブジェクトを生成します。そのサンプルを載せておきます。

EventManager.cs
public class EventManager : MonoBehaviour
{
    public static void CallEvent(string eventName)
    {
        //AddComponentでオブジェクトを生成
        EventManager eventManager = (new GameObject("適当なオブジェクト名")).AddComponent<EventManager>();
        //コルーチン呼び出し(この場合は正常に実行できる)
        eventManager.StartCoroutine("Event");
    }

    //コルーチン関数"Event"を定義
    IEnumerator Event()
    {
        Debug.Log("あいうえお");

        //マウス左クリックを待つ処理
        yield return new WaitUntil(() => Input.GetMouseButtonDown(0));

        Debug.Log("かきくけこ");
    }
}

はい、これでエラーなく正常に実行できました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away