1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Craft EggAdvent Calendar 2021

Day 19

UnityのCoroutineのつまづきやすいところまとめ

Last updated at Posted at 2021-12-27

本記事はCraft Egg Advent Calendar 2021の12/19の記事です。(投稿が遅れ申し訳ありません)
12/18の記事は@arumaniさんの「iPhoneで3D空間に入って撮影できる『Unity Virtual Camera』」でした。

はじめに

株式会社Craft EggでUnityクライアントエンジニアをしている鈴木です。
UnityにおけるCoroutineのよく「どうだったっけ?」ってなるつまづきやすいところをまとめました。
基本的な項目が多めになっていますが、非同期処理ということもあり、意外と直面した時に気づくことができないこともありますので、Coroutine周りでつまづいた時にチェックするリスト代わりに使えるものになればと思います。

Coroutineのつなぎ方

yield returnとmovenext検証

    void Hoge()
    {
        Debug.Log($"メインコルーチン開始 :  {Time.frameCount}");
        //任意のコルーチンを実行
        //StartCoroutine(MoveNextCoroutine());
    }

    
    private IEnumerator YieldReturnCoroutine()
    {
        Debug.Log($"YieldReturnCoroutine開始 :  {Time.frameCount}");

        yield return SubCoroutine();

        Debug.Log($"YieldReturnCoroutine終了 : {Time.frameCount}");
    }
    
    private IEnumerator MoveNextCoroutine()
    {
        Debug.Log($"MoveNextCoroutine開始 :  {Time.frameCount}");

        IEnumerator coroutine = SubCoroutine();
        while(coroutine.MoveNext()) { yield return coroutine.Current; }

        Debug.Log($"MoveNextCoroutine終了 : {Time.frameCount}");
    }
    
    private IEnumerator SubCoroutine()
    {
        Debug.Log($"SubCoroutine開始 : {Time.frameCount}");
        Debug.Log($"SubCoroutine終了 : {Time.frameCount}");
        yield break;
    }
YieldReturnCoroutine
メインコルーチン開始 :  1
YieldReturnCoroutine開始 :  1
SubCoroutine開始 : 1
SubCoroutine終了 : 1
YieldReturnCoroutine終了 : 2
MoveNextCoroutine
メインコルーチン開始 :  1
MoveNextCoroutine開始 :  1
SubCoroutine開始 : 1
SubCoroutine終了 : 1
MoveNextCoroutine終了 : 1

Coroutineの止め方

  • StopCoroutineだけだと破棄されない
    • 一度null埋めをすることで破棄される
    • null埋めしなかった場合止めた部分から再開される
  • 開始したMonoBehaviorからしか止められない
  • GameObjectが非アクティブになったタイミングでCoroutineも止まる
    • 非アクティブなGamerObjectでは開始もできない
  • startしたときと同じ記法でないと止めることができない

Coroutineのnull埋め検証

    private IEnumerator mainCoroutine;
    
    void Start ()
    {
        Debug.Log($"メインコルーチン開始");
        mainCoroutine = MainCoroutine();
        StartCoroutine(mainCoroutine);
        // 任意のサブコルーチンを実行
        StartCoroutine(SubCoroutineB());
    }

    private IEnumerator MainCoroutine()
    {
        Debug.Log("MainCoroutine 1");
        yield return null;
        Debug.Log("MainCoroutine 2");
        yield return null;
        Debug.Log("MainCoroutine 3");
    }
    
    private IEnumerator SubCoroutineA()
    {
        yield return null;
        StopCoroutine(mainCoroutine);
        Debug.Log("Stop MainCoroutine");
        yield return mainCoroutine;
    }
    
    private IEnumerator SubCoroutineB()
    {
        yield return null;
        StopCoroutine(mainCoroutine);
        mainCoroutine = null;
        Debug.Log("Stop MainCoroutine");
        mainCoroutine = MainCoroutine();
        yield return mainCoroutine;
    }
SubCoroutineA
メインコルーチン開始
MainCoroutine 1
MainCoroutine 2
Stop MainCoroutine
MainCoroutine 3
SubCoroutineB
メインコルーチン開始
MainCoroutine 1
MainCoroutine 2
Stop MainCoroutine
MainCoroutine 1
MainCoroutine 2
MainCoroutine 3

Coroutineの実行者の検証

    private IEnumerator mainCoroutine;
    
    private MonoBehaviour cachedCoroutineOwner;
    
    void CoroutineStart(MonoBehaviour coroutineOwner)
    {
        Debug.Log($"メインコルーチン開始");
        mainCoroutine = MainCoroutine();
        coroutineOwner.StartCoroutine(mainCoroutine);
        // 任意のサブコルーチンを実行
        StartCoroutine(SubCoroutineB());
        cachedCoroutineOwner = coroutineOwner;
    }

    private IEnumerator MainCoroutine()
    {
        Debug.Log("MainCoroutine 1");
        yield return null;
        Debug.Log("MainCoroutine 2");
        yield return null;
        Debug.Log("MainCoroutine 3");
    }
    
    private IEnumerator SubCoroutineA()
    {
        yield return null;
        StopCoroutine(mainCoroutine);
        Debug.Log("Stop MainCoroutine");
    }
    
    private IEnumerator SubCoroutineB()
    {
        yield return null;
        cachedCoroutineOwner.StopCoroutine(mainCoroutine);
        Debug.Log("Stop MainCoroutine");
    }
    
SubCoroutineA
MainCoroutine 1
MainCoroutine 2
Stop MainCoroutine
MainCoroutine 3
SubCoroutineB
MainCoroutine 1
MainCoroutine 2
Stop MainCoroutine

その他

  • Coroutineから戻り値を受け取ることもできる
    • 明示的に型変換する必要あり
  • StopAllCoroutineでMonoBehaviorが保持しているCoroutineをすべて止めることができる
    • StartをIEnumratorにしていたらそれも止まるので注意
  • DoTweeenの終わりを待つ方法

Coroutineから戻り値を受け取る

    private void CoroutineStart()
    {
        StartCoroutine(MainCoroutine());
    }

    private IEnumerator MainCoroutine()
    {
        IEnumerator subCoroutine = SubCoroutine();
        yield return subCoroutine;
        Debug.Log($"subCoroutine.Current : {(string)subCoroutine.Current}");
    }

    private IEnumerator SubCoroutine()
    {
        yield return "SubCoroutine is End";
    }
subCoroutine.Current : SubCoroutine is End

参考記事

終わりに

今回はCoroutineのつまづきやすいところをまとめてみました。最近は非同期処理でCoroutineを採用することは少ないですが、ちょっとした個人開発などではまだまだ現役かと思いますので参考になれば幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?