IEnumerator 协程 全称协同程序

IEnumerator 协程 全称协同程序

 每次 执行协程 时,都会新建一个新()线程去执行,第二次执行不会影响上一次的执行,
     结论是:协程适用于同一时间只运行一份函数的情况,如果同一时间运行多份同一个协程就会难以管理
    void Start()
    {
        for (int i = 0; i < 7; i++)
        {
            StartCoroutine(SampleFunc(7));  //第二次执行时,会重新开启伪新线程执行,不会影响打断第一次执行,这里会开启7个伪线程,每个线程单独执行SampleFunc()函数
        }
    }
    IEnumerator SampleFunc(int a)
    {
        while (a != 0)
        {
            a--;
            Debug.Log("a=============== "+ a);   //输出了 7*7=49 句 a 的值
            yield return new WaitForSeconds(0.1f);
        }
    }
 
表达式
yield return null;  //等1帧执行.暂停协同程序,下一帧再继续往下执行. 通知协程管理器,我到这个点要中断一下,下一帧从这个地方运行而已.
yield return 0;      //同yield return null;,数字改多大没用,都是等一帧
yield return 666; //同yield return null;,数字改多大没用,都是等一帧
yield break; //不在执行下面的语句,直接rerun
yield return asynaOperation; //等待异步操作执行完毕后执行
yield return StartCoroutine(coroutine); //等待子协程执行完毕后再执行
yield return  WWW();    在WWW下载完成之后……waits for a web request to complete (resumes as if WaitForSeconds or null)
yield return new WaitForEndOfFrame(); //等待帧结束,等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前。用在while循环里减少死机
yield return new WaitForSeconds(0.3f);//等待0.3秒 , 一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后注意:受Time.timeScale影响,当Time.timeScale = 0f 时,yield return new WaitForSecond(x) 将不会满足。
yield return new WaitForFixedUpdate(); // 所有脚本上的FixedUpdate函数已经执行调用之后持续
yield return new WaitUntil:将协同执行直到 当输入的参数(或者委托)为true的时候……  || yield return new WaitUntil(() => frame >= 10);
yield return new  WaitWhile:将协同执行直到 当输入的参数(或者委托)为false的时候…… || yield return new WaitWhile(() => frame < 10);

协程其实就是一个IEnumerator(迭代器),IEnumerator 接口有两个方法 Current 和 MoveNext() ,只有当MoveNext()返回 true时才可以访问 Current,否则会报错。迭代器方法运行到 yield return 语句时,会返回一个expression表达式并保留当前在代码中的位置。 当下次调用迭代器函数时执行从该位置重新启动。

Unity在每帧做的工作就是:调用 协程(迭代器)MoveNext() 方法,如果返回 true ,就从当前位置继续往下执行。


yield return 被会“翻译”为一个 IEnmerator 对象,这个对象实现的 MoveNext() 包含函数内所有 yield return 的处理

函数内有多少个 yield return 在对应的 MoveNext() 就会返回多少次 true (不包含嵌套)。

另外非常重要的一点的是:同一个函数内的其他代码(不是 yield return 语句)会被移到 MoveNext 中去,也就是说,每次 MoveNext 都会顺带执行同一个函数中 yield return 之前,之后 和两个 yield return 之间的代码。



协程不是线程,也不是异步执行的,是Unity每帧LateUpdate()之后都会去处理的函数


协程执行流程

1 如果 [gameObject激活] 并且 [脚本.enable=true ] 状态 下, StartCoroutine启动了协程 ,协程会立即运行到第一个 yield return 语句处,控制权交给外部

2. 等待Unity在下一帧(Frame)LateUpdate()之后

3.检查协程是否允许的条件 : 

脚本.enabled = false 协程会照常运行

a.检测 gameObject 是否处于激活(active) ,不激活不运行

b.检测 yield return 后面的表达式,如果满足就继续向下执行


IEnumerator 协程  全称协同程序

1.必须在MonoBehaviour或继承于MonoBehaviour的类中调用 yield coroutine。

2.StartCoroutine所在脚本物体必须是激活的.才能执行不报错.


MonoBehaviour.StartCoroutine方法即可开启一个协同程序,


StopCoroutine(methodName())//来终止一个协同程序,

StopAllCoroutines()//来终止所有可以终止的协同程序,

但这两个方法都只能终止该MonoBehaviour中的协同程序。

MonoBehaviour.enabled = false 协程会照常运行,gameObject.SetActive(false) 停止,即使在Inspector把  gameObject 激活还是没有继续执行



//yield return 被会“翻译”为一个 IEnmerator 对象

//yiled return 本质上和return作用一样,将当前函数返回。只不过下一次再调用这个函数,可以从yiled return的下一句开始执行,函数本身的变量也都会一直保存上一次调用的状态。

//yield return的作用是在执行到这行代码之后,将控制权立即交还给外部。yield return之后的代码会在外部代码再次调用MoveNext时才会执行,直到下一个yield return——或是迭代结束

yield return expression; //只有表达式完全执行结束才会继续执行后面的代码


结束返回:

在迭代器块中用于向枚举数对象提供值或发出迭代结束信号。它的形式为下列之一⑥:

  yield return <expression_r>;

  yield break;


//==========================列0=============================

    void Start()

    {

        StartCoroutine(WaitEnd (5f)); // 瞬间执行 WaitEnd函数 ,和下面的函数

        StartCoroutine (WaitFrameEnd());// 瞬间执行 WaitFrameEnd函数 ,和下面的函数        

StartCoroutine (WaitFixedUpdate());// 瞬间执行 WaitFixedUpdate函数 ,和下面的函数    

    }

 

    IEnumerator WaitEnd(float time)

    {    // 执行同时,其他函数也再并行

        yield return new WaitForSeconds(time);

            // 5秒后到这里 ,执行这里的

        Debug.Log ("WaitForSeconds:"+time);

    }

 

    IEnumerator WaitFrameEnd()

    {    

        yield return new WaitForEndOfFrame();

         // 等待当前帧结束 

        Debug.Log ("WaitForEndOfFrame:"+Time.time);

    }

 

    IEnumerator WaitFixedUpdate()

    {

        yield return new WaitForFixedUpdate();

            // 等待每次 Update 执行一次后调用

        Debug.Log ("WaitForFixedUpdate:"+Time.time);

    }


//==========================列1=============================

IEnumerator WaitAndshen()

{

yield return new WaitForSeconds(0.3f);

//上面的时间到了才能执行下面的.

}

//注意 StartCoroutine 所在脚本物体必须是激活的.才能执行不报错.

StartCoroutine( WaitAndshen());

//==========================列2 带参数的协程=============================

 void Start()

 {

StartCoroutine(_PlayLoopSound(clip, delay, time, fadeInTime, fadeOutTime));

 }


    IEnumerator _PlayLoopSound(AudioClip clip, float delay, float time, float fadeInTime, float fadeOutTime)

    {

    }