UnityでStartCoroutineメソッドを実行した際に、なぜかNullReferenceExceptionのエラーが発生して2時間ほどハマったので、その解決策をメモしておきます。
結論から言うと、Update()メソッド以外のメソッドからコルーチン処理を実行する(StartCoroutineメソッドを実行する)場合は、そのコルーチン処理を呼び出すためのオブジェクトをnewで直接生成してはならないようです。
StartCoroutineの使い方について解説している他の参考サイトなどでは、Update()メソッド内からStartCoroutineを実行している事例しか見当たらなかったため、今回のように他のメソッドから実行したい場合はどうすればよいのか悩みました。
まず、Updateメソッド内からコルーチン処理を呼び出す事例を載せておきます。
public class EventManager : MonoBehaviour
{
void Update()
{
//Updateメソッド内からコルーチン呼び出し(この場合は正常に実行できる)
StartCoroutine("Event");
}
//コルーチン関数"Event"を定義
IEnumerator Event()
{
Debug.Log("あいうえお");
//マウス左クリックを待つ処理
yield return new WaitUntil(() => Input.GetMouseButtonDown(0));
Debug.Log("かきくけこ");
}
}
出力結果を確認すると、正常に実行できていました。
次に、エラーが発生した事例を載せておきます。
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メソッドを使ってオブジェクトを生成します。そのサンプルを載せておきます。
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("かきくけこ");
}
}
はい、これでエラーなく正常に実行できました。