早在写cocos-lua时就说要认真研究一下协程,然而…
参考
twisted oak
Edison
丘丘雷雷的博客
王选易
中辽普坦的专栏
namespace System.Collection{
public interface IEnumerable{
IEnumerator GetEnumerator();
}
}
任何继承了IEnumerable接口的都可以通过foreach来遍历。
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();
}
}
}
}
不管什么时候,如果你想创建一个能够经历多个逻辑帧的流程,但是不适用多线程或多进程,那你就需要把一个任务来分割成多个任务,然后在下一帧继续执行这个任务。
首先来一个经典的斐波拉切实现
[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);
}
}
开启一个协程。协程的调用几乎没有任何性能开销,StartCoroutine一般都会立即返回,然而你也可以获得返回结果的值。但会等到协程结束才能生效。
StartCoroutine()生成一个Coroutine实例,第一次运行IEnumerator然后返回一个yield值。
游戏逻辑在每帧执行。例如Update会在每帧调用,unity会在没帧调用保存的Coroutines并且处理IEnumerators返回的值。
本质和return作用一样,将当前函数返回,只不过下次再调用这个函数是,会从yield return的下一句开始执行,函数本身的变量也都会一直保存上一次调用的状态,知道最后一次return,协程的状态才会被清除。
一个协程可以在任何地方用yield暂停,yield return的值决定了什么时候恢复协程。
Yield return可以发挥任意YieldInstruction
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);
}