Unity协程以及迭代器

早在写cocos-lua时就说要认真研究一下协程,然而…

参考
twisted oak
Edison
丘丘雷雷的博客
王选易
中辽普坦的专栏

IEnumerable


namespace System.Collection{
    public interface IEnumerable{
        IEnumerator GetEnumerator();
    }
}

任何继承了IEnumerable接口的都可以通过foreach来遍历。

IEnumerator


namespace System.Collection{
    public interface IEnumerator{
        bool MoveNext();
        object Current(get;);
        void Reset();
    }
}

.net官方关于IEnmerator的例子

public class PeopleEnum : IEnumerator{
    public Person[] _people;
    int position = -1;
    public PeopleEnum(Person[] list){
        _people = list;
    }

    public bool MoveNext(){
        position++;
        return (position < _people.Length);
    }

    object IEnumerator.Current{
        get{return Current}
    }

    public Person Current{
        get{
            try{
                return _people[position];
            }catch(IndexOutOfRangeException ){
                throw new InvalidOperationException();
            }
        }
    }
} 

Time slicing

不管什么时候,如果你想创建一个能够经历多个逻辑帧的流程,但是不适用多线程或多进程,那你就需要把一个任务来分割成多个任务,然后在下一帧继续执行这个任务。

斐波拉切

首先来一个经典的斐波拉切实现
[1,1,2,3,5,8…]

IEnumerator Fibonacci(){
    int Fkm2 = 1;
    int Fkm1 = 1;
    yield return 1; 
    yield return 1;
    while(Fkm1 + Fkm2 < int.MaxValue){
        int Fk = Fk2 + Fk1;
        Fk2 = Fk1;
        Fk1 = Fk;
        yield return Fk;
    }
}

void Start(){
    IEnumerator fib = Fibonacci();

    for(i = 0 ; i < 10 ;i ++){
        if(!fib.MoveNext()){
            break;
        }

        Debug.Log((int)fib.Current);
    }
}

Unity协程


StartCoroutine

开启一个协程。协程的调用几乎没有任何性能开销,StartCoroutine一般都会立即返回,然而你也可以获得返回结果的值。但会等到协程结束才能生效。

StartCoroutine()生成一个Coroutine实例,第一次运行IEnumerator然后返回一个yield值。
游戏逻辑在每帧执行。例如Update会在每帧调用,unity会在没帧调用保存的Coroutines并且处理IEnumerators返回的值。

yield return

  • 本质和return作用一样,将当前函数返回,只不过下次再调用这个函数是,会从yield return的下一句开始执行,函数本身的变量也都会一直保存上一次调用的状态,知道最后一次return,协程的状态才会被清除。

  • 一个协程可以在任何地方用yield暂停,yield return的值决定了什么时候恢复协程。

YieldInstruction

Yield return可以发挥任意YieldInstruction

  1. yield return null;暂停协同程序,下一帧再继续执行
  2. yield new WaitForFixedUpdate();暂停协同程序,等到下一次调用FixedUpdate方法时再继续往下执行
  3. yield return new WatiForSeconds(2);暂停协同程序,2秒后再继续往下执行
  4. yield return StartCoroutine(“SomeCortoutineMethod”)暂停此协同程序,开启SomeCortoutineMethod协同程序
  5. yield return WWW
IEnumerator Start(string url){
    WWW www = new WWW(url);
    yield return www;
    ...
}
YieldInstruction y;
if(something){
    y = null;
}else if(something){
    y = new WatiForEndOfFrame();
}else{
    y = new WaitForSeconds(1.0f);
}

yield return y;

协程嵌套


IEnumerator UntilTrueCoroutine(Func fn){
    while(!fn()) yield return null; 
}

Coroutine UntilTrue(Func fn){
    return StartCoroutine(UntilTrueCoroutine(fn));
}

IEnumerator SomeTask(){
    yield return UntilTrue(() => _lives < 3); 
}

你可能感兴趣的:(unity)