解决Unity协程无法同步返回的问题

Unity的协程是轻量的异步解决方案,但是每调用一次yield就必须等下一帧才能继续,这一点带来了很多约束。

 

比如如下代码:

void OnEnable()
{
    StartCoroutine(_Do());
}

IEnumerator _Do()
{
    Debug.Log("[A]Frame " + Time.frameCount);
    yield return null;
    Debug.Log("[B]Frame " + Time.frameCount);
}

 

 

 

当然,也会想到用一些Trick欺骗过去

IEnumerator Start()
{
    Debug.Log("[0]frame: " + Time.frameCount);

    yield return Foo1();

    yield return Foo2();
}

IEnumerator Foo1()
{
    Debug.Log("[1]frame: " + Time.frameCount);
    if (Time.time < 0)//always false
        yield return null;
    Debug.Log("[2]frame: " + Time.frameCount);
}

IEnumerator Foo2()
{
    Debug.Log("[3]frame: " + Time.frameCount);

    yield return null;
}

可是编译器并不吃这一套

 

 

 

那么解决方法也很简单,就是用迭代器再封装一层。

并把yield return true作为非异步返回的标记:

 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class CoroutineTest : MonoBehaviour
{
    void OnEnable()
    {
        StartCoroutine(ToFixedCoroutine(_Do()));
    }

    IEnumerator _Do()
    {
        Debug.Log("[A]Frame " + Time.frameCount);
        yield return true;
        Debug.Log("[B]Frame " + Time.frameCount);
    }

    public static IEnumerator ToFixedCoroutine(IEnumerator enumerator)
    {
        var parentsStack = new Stack<IEnumerator>();
        var currentEnumerator = enumerator;

        parentsStack.Push(currentEnumerator);

        while (parentsStack.Count > 0)
        {
            currentEnumerator = parentsStack.Pop();

            while (currentEnumerator.MoveNext())
            {
                var subEnumerator = currentEnumerator.Current as IEnumerator;
                if (subEnumerator != null)
                {
                    parentsStack.Push(currentEnumerator);
                    currentEnumerator = subEnumerator;
                }
                else
                {
                    if (currentEnumerator.Current is bool && (bool)currentEnumerator.Current) continue;
                    yield return currentEnumerator.Current;
                }
            }
        }
    }
}

 

 

 

 

这样就可以同步返回了

ToFixedCoroutine函数经过一些嵌套的测试,使用起来还算稳定。

 

posted @ 2017-03-10 21:49  HONT  阅读(3320)  评论(0编辑  收藏  举报