いぬおさんのおもしろ数学実験室

おいしい紅茶でも飲みながら数学、物理、工学、プログラミング、そして読書を楽しみましょう

Unityで、自作クラス内でコルーチンを呼ぶ

自分で作ったクラス(特に継承はしていない)の中でコルーチンを呼ぶ必要があり、試してみました。次のコードではエラーが出ます。

   //----------------

   class testclassA {
        public IEnumerator test1() {
            Coroutine cr;
            cr = StartCoroutine(test2());//①
            yield return cr;
            StartCoroutine(test3());//②
        }
        public IEnumerator test2() {
            yield return new WaitForSeconds(3f);
            Debug.Log("■3秒経過");
        }
        public IEnumerator test3() {
            yield return new WaitForSeconds(2f);
            Debug.Log("■さらに2秒経過");
        }
    }
    //--------------------------
    testclassA A = new();

    //--------------------------

testclassAというクラスを作り、中でコルーチンを3つ定義しています。コルーチンtest1()では、まずコルーチンtest2()を呼び、test2()が終了したらtest3()を呼ぶようにしています。クラスのインスタンス

testclassA A = new();

で生成しておき、

StartCoroutine(A.test1());

を実行すればよさそうなのですが、コンパイルの段階でエラーが出ました。なお、

yield return cr;

でひとつのコルーチンが終了したら次のコルーチンを実行できるのでした。詳しくは以下の記事を。

www.omoshiro-suugaku.com

エラーは①、②のところで出ます。エラーコードはCS0120。「staticでない××」のような感じなので、適当にコルーチンにstaticをつけたりしてみましたがダメ。ネットであれこれ検索しました。結局、コルーチンはMonoBehaviourを継承したクラス内からでないと使えないのだそう。ほう、なるほどと思ってクラスの定義を次のように変更しました。クラス名はtestclassBに変え、メソッドも別の名前にしました。

    //--------------------------

    class testclassB : MonoBehaviour {//MonoBehaviour を継承
        public IEnumerator test3() {
            Coroutine cr;
            cr = StartCoroutine(test4());
            yield return cr;
            StartCoroutine(test5());
        }
        public IEnumerator test4() {
            yield return new WaitForSeconds(3f);
            Debug.Log("■3秒経過");
        }
       public IEnumerator test5() {
            yield return new WaitForSeconds(2f);
            Debug.Log("■さらに2秒経過");
        }
    }
    //--------------------------
    testclassB B;

    B = new();//インスタンスを生成

    //--------------------------

しかし、今度は

StartCoroutine(B.test3());

の実行時にエラーが出ました。調べるとBがnullになっています。さらにネットでまた調べると、どうやらMonoBehaviour を継承したクラスは

    B = new();

ではインスタンスを作れないらしいです。

    B = new();

の代わりに、以下でうまくいきました。

        var go = new GameObject("keshitene");//"keshitene"は他、適当でOK
        B = go.AddComponent<testclassB>();//testclassBをnew

これ、要するにMonoBehaviour を継承したクラスはコンポーネントだということを意味しそうです。

 

 まとめておきましょう。

    //--------------------------

    class testclassB : MonoBehaviour {//MonoBehaviour を継承
        public IEnumerator test3() {
            Coroutine cr;
            cr = StartCoroutine(test4());
            yield return cr;
            StartCoroutine(test5());
        }
        public IEnumerator test4() {
            yield return new WaitForSeconds(3f);
            Debug.Log("■3秒経過");
        }
        public IEnumerator test5() {
            yield return new WaitForSeconds(2f);
            Debug.Log("■さらに2秒経過");
        }
    }
    //--------------------------

        var go = new GameObject("keshitene");//"keshitene"は他、適当でOK
        B = go.AddComponent<testclassB>();//testclassBをnew

インスタンスBを生成しておき、

StartCoroutine(B.test3());

でうまくいきます!

 

実はMonoBehaviourを継承していなくても、内部でコルーチンを呼ぶことはできました。ただこちらは個人的には手軽な方法とは思えず、結局今回のこの方法でいくことにしました。今回紹介したやり方ならインスタンスの生成が少し面倒になるくらいで、スッキリしている印象です。