IEnumrator やコルーチン関係の挙動についてのメモ

コルーチンについての挙動についてまとめる。

目次

  1. 概要
  2. 実際の中身
  3. コード全文

概要

ここでは、実際に遭遇した IEnumratorの使い方 や UnityのStartCorutine などの挙動について遭遇するたびにこれであっているんだっけ?と 不安に駆られるため、それらの 挙動だけ について記述したものです。 ここでは、どうしてそうなるかについては、他を当たってください。

※サンプルコードはBehaviorクラス内のものとする。

環境 Unity2018.4.9 VisualStudio2019 Community

実際の中身

IEnumrator を変数で保持し、MoveNextで実行した場合の挙動

サンプルコード

private IEnumerator coltine;

void Start()
{
    coltine = normalColutine();
}

void Update () 
{
    if(null == coltine)
    {
        return;
    }

    bool next = coltine.MoveNext();
    if(next)
    {
        Debug.Log("まだ存在している");
    }
    else
    {
        Debug.Log("存在していない");
        coltine = null;
    }
}

private IEnumerator normalColutine()
{
    yield return 0;
    yield return 1;
    yield return 2;
    yield return 3;
}

この時のログの出力は以下の通り まだ存在している まだ存在している まだ存在している まだ存在している 存在していない

理解補足

この場合の挙動としては、MoveNext自体は5回実行可能で、5回目にbool nextの値がfalseで返却されます。 1回目:yield return 0; の所まで 2回目 : yiled return 1; の所まで 3回目:yield return 2; の所まで 4回目 : yiled return 3; の所まで 5回目:残りの部分まで

MoveNext自体の挙動自体は、関数が終了したタイミングがMoveNext自体がfalseになるタイミングになる。

yield break;を使用した場合の挙動としては以下の通り

MoveNextの動かし方は先ほどの準拠

yield return の場合

private IEnumerator breakColutine()
{
    yield return 0;
    yield break;
}

この場合のログの出力は以下の通り まだ存在している 存在していない

yield break;が呼び出された時点で、MoveNextの返り値がfalseになる。

IEnumratorの中からStartCorutineを呼び出した挙動について

IEnumerator で 実装されているものからStartCorutine()を呼び出した際の挙動についてです。 パターンとして2パターン - IEnumrator をMoveNextで行った場合 - StartCoroutineで呼び出した場合

呼び出す IEnumratorの中身としては以下の通り

private IEnumerator callCorutine()
{
    yield return 0;
    Debug.Log("call 1");
    yield return StartCoroutine(normalColutine());

    Debug.Log("call 2");
}

private IEnumerator normalColutine()
{
    Debug.Log("col1");
    yield return 0;
    Debug.Log("col2");
    yield return 0;
    Debug.Log("col3");
    yield return 3;
    Debug.Log("col4");
    yield return 5;
}

IEnumratorで呼び出した場合

callCorutineをMoveNextで呼び出した場合の出力

call1

cal1

call2

col2

col3

col4

となり、それぞれが別々に動き出すイメージです。 単純にこれは、MoveNextをUpdate側で呼び出している影響かなと思います。

StartCorutineで呼び出した場合

call1

col1

col2

col3

col4

coll2

となり、StartCorutineで呼び出した先でさらに yield return StartCorutine で呼び出した場合は、そのコルーチンが終了してから、1つ目の処理の続きが実行されます。

ただ、yield return をつけない場合

call 1

col1

call2

col2

col3

col4

となります。

コード全文

using System.Collections;
using UnityEngine;

public class CorutineSample : MonoBehaviour 
{

private bool check = false;

private IEnumerator coltine;

// Use this for initialization
void Start () 
{
    //coltine = normalColutine();
    //coltine = breakColutine();
    coltine = callCorutine();
    //StartCoroutine(callCorutine());
}
    
// Update is called once per frame
void Update () 
{
    if(null == coltine)
        {
        return;
        }

    bool next = coltine.MoveNext();
    if(next)
        {
        Debug.Log("まだ存在している");
        }
    else
        {
        Debug.Log("存在していない");
        coltine = null;
        }   
}

/// <summary>
/// Whileを使用したコルーチンです。
/// </summary>
/// <returns></returns>
private IEnumerator whileColutine()
{
    int ban = 0;
    while(false == check)
        {
          if(Input.GetKey(KeyCode.Space))
             {
            check = true;
             }
        ///万が一の時用のセーフティ
        if(ban >= 10)
              {
            check = true;
              }
          ban++;
          Debug.LogFormat("whileColutine:{0}",ban);
        }


    IEnumerator col = normalColutine();
    int val = 0;
    while(val != 5)
        {
        col.MoveNext();

        if(null != col.Current)
            {
            val = (int)col.Current;
            }
        Debug.Log("ここ通っているよ");
    }

    Debug.Log("while Corutine");
    yield return null;
 }

/// <summary>
/// 通常のコルーチンの処理
/// </summary>
/// <returns></returns>
private IEnumerator normalColutine()
{
    Debug.Log("col1");
    yield return 0;
    Debug.Log("col2");
    yield return 0;
    Debug.Log("col3");
    yield return 3;
    Debug.Log("col4");
    yield return 5;
}

/// <summary>
/// breakのコルーチン
/// </summary>
/// <returns></returns>
private IEnumerator breakColutine()
 {
    yield return 0;
    yield break;
 }

private IEnumerator ifColutine()
{
    if(check)
    {
        Debug.Log("IfColutine check=True");
        yield return 0;
    }
    else
    {
    Debug.Log("IfColutine Check = false");
    yield break;
    }
    Debug.Log("IfColutine End");
    yield break;
}

private IEnumerator breakColuine()
{
    Debug.Log("breakColutine 1");
    yield break;
    //こっちは通らない
    Debug.Log("breakColutine 2");
}

/// <summary>
/// IEnumeratorからStartCorutineが呼び出された場合のもの
/// </summary>
/// <returns></returns>
private IEnumerator callCorutine()
{
    yield return 0;
    Debug.Log("call 1");
    yield return StartCoroutine(normalColutine());
    Debug.Log("call 2");
}
}