お米 is ライス

C#やらUnityやらを勉強していて、これはメモっといたほうがええやろ、ということを書くつもりです

UnityのCoroutine的なものを自前で実装する

Coroutine

コルーチンはこんな感じで使えるやつだ

void Awake()
{
    StartCoroutine(Test());
}

IEnumerator Test1()
{
    DoSomething();
    yield return null;
    Hoge();
    yield break;
}

コルーチンのネストもできて

void Awake()
{
    StartCoroutine(Test2())
}

IEnumerator Test2()
{
    Debug.Log("1");
    yield return null; 
    Debug.Log("2");
    yield return StartCoroutine(Test3())
    Debug.Log("3");
    yield break;
}

IEnumerator Test3()
{
    Debug.Log("A");
    yield return null;
    Debug.Log("B");
    yield break;
}

こんな感じにすると1, 2, A, B, 3の順で出力される(たぶん)。

Coroutineの問題点

この記事の目的はあくまで「実装してみよう!!」というものであり問題点を指摘することが目的ではないが、実装への動機づけのために言及しておく。

イテレータから何が返ってくるかわからな

イテレータをネストしているとき、つまりTest2関数の中でTest3関数を呼んでいるようなことをしているときの話である。
例えばTest3の中でのある処理が成功したか失敗したかをTest2で知る必要があったとしよう。
それを知るにはTest3の最後にyield return falseなどとしてやればよい。
しかしさらにTest3の中からさらにTest4へとネストしたい場合、yield return StartCoroutine(Test4())ともしてやらなければならない。
こうなった場合、関数の返り値の型をIEnumerator<bool>などと指定することは不可能となり、単にIEnumeratorと書かなければならなくなる。
そうするともはやイテレータから何が返ってくるのかがわからなくなり、あるいは無法地帯のような状況になってしまうかもしれない。
そうならないためにも、UnityにおけるCoroutineのようなものを自前で用意しようということなのである。

実装

というわけで、自前で実装してみたのがこちらになります。 gist.github.com

こうしておくとイテレータが何返してくるのかわかって安心だよねーという話でした。
意外と簡単に実装できますね。

使い方

こんな感じで使うよー\(^o^)/

private Iterator iterator;
private bool flag = false;

void Awake()
{
    iterator = new Iterator();
}

void Update()
{
    iterator.Progress();
}

IEnumerator<IteratorResult> Hoge()
{
    yield return IteratorResult.Continue;
    yield return IteratorResult.Nest(Fuga());
    yield return IteratorResult.Completed;
}

IEnumerator<IteratorResult> Fuga()
{
    yield return IteratorResult.Continue;
    if(!flag)
    {
        yield return IteratorResult.Canceled;
        yield break;
    }
    
    yield return IteratorResult.Completed;
}

まとめ

UnityのCoroutineを自前で実装してみたよ! 他にいい方法があったら教えてくり!!