zoukankan      html  css  js  c++  java
  • yield学习续:yield return迭代块在Unity3D中的应用——协程

    必读好文推荐:

    Unity协程(Coroutine)原理深入剖析

    Unity协程(Coroutine)原理深入剖析再续

    上面的文章说得太透彻,所以这里就记一下自己的学习笔记了。

    首先要说明的是,协程并不是线程,协程是运行在主线程中的,是和主线程同步执行的代码,不同的地方是运行的方法可以被yield return在当前帧进行打断,到下一帧后可以继续从被打断的地方继续运行。

    下面我们看一个示例,场景中有一个空的GameObject对象,其绑定了下面的脚本:

    复制代码
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class Test : MonoBehaviour
     5 {
     6     int frame = 0;
     7 
     8     void Start ()
     9     {
    10         this.StartCoroutine(CountDown());
    11     }
    12     
    13     void Update ()
    14     {
    15         Debug.Log("Now is frame: " + (++frame));
    16     }
    17 
    18     IEnumerator CountDown()
    19     {
    20         Debug.Log("step - 1");
    21         yield return null;
    22         Debug.Log("step - 2");
    23         yield return null;
    24         Debug.Log("step - 3");
    25         yield return null;
    26         Debug.Log("step - 4");
    27     }
    28 }
    复制代码

    下面是执行的结果:

    下面我们看看运行的逻辑是如何的:

    当进入Start方法时开始启动协程,这时候协程开始运行,输出“step1”后遇到第一个yield return后暂停本帧的运行,接下来进入Update方法输出“frame1”,由于协程调用是在Update之后,所以第二帧开始后,先执行了第二个Update输出“frame2”,然后从协程的上次暂停处继续执行,输出“step2”后遇到第二个yield return后暂停本帧的运行,如此反复,当输出“step4”后发现方法已经执行完毕,协程结束。

    下面看看yield break的效果,这个语句会立即中断协程的运行,代码如下:

    复制代码
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class Test : MonoBehaviour
     5 {
     6     int frame = 0;
     7 
     8     void Start ()
     9     {
    10         this.StartCoroutine(CountDown());
    11     }
    12     
    13     void Update ()
    14     {
    15         Debug.Log("Now is frame: " + (++frame));
    16     }
    17 
    18     IEnumerator CountDown()
    19     {
    20         Debug.Log("step - 1");
    21         yield return null;
    22         Debug.Log("step - 2");
    23         yield return null;
    24         Debug.Log("step - 3");
    25         yield break;
    26         Debug.Log("step - 4");
    27     }
    28 }
    复制代码

    下面是运行的结果:

    我们可以发现“step4”已经运行不到了。

    yield的返回值,我们可以返回null或者数字0,效果是一致的,同时还可以返回3个对象,分别如下:

    yield return new WaitForFixedUpdate();

    ·等待直到下一个固定帧速率更新函数。

    yield return new WaitForEndOfFrame();

    ·等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前。

    yield return new WaitForSeconds(1);

    ·在给定的秒数内,暂停协同程序的执行。

    下面我们来看一个例子,修改第一个例子的Test.cs:

    复制代码
     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class Test : MonoBehaviour
     5 {
     6     int frame1 = 0;
     7     int frame2 = 0;
     8     int frame3 = 0;
     9 
    10     void Start ()
    11     {
    12         this.StartCoroutine(CountDown());
    13         this.StartCoroutine(CountDown_WaitForFixedUpdate());
    14         this.StartCoroutine(CountDown_WaitForEndOfFrame());
    15         this.StartCoroutine(CountDown_WaitForSeconds());
    16     }
    17     
    18     void Update ()
    19     {
    20         Debug.Log("Update is frame: " + (++frame1));
    21     }
    22 
    23     void FixedUpdate ()
    24     {
    25         Debug.Log("FixedUpdate is frame: " + (++frame2));
    26     }
    27 
    28     void LateUpdate ()
    29     {
    30         Debug.Log("LateUpdate is frame: " + (++frame3));
    31     }
    32 
    33     IEnumerator CountDown()
    34     {
    35         Debug.Log("yield - step - 1");
    36         yield return null;
    37         Debug.Log("yield - step - 2");
    38         yield return null;
    39         Debug.Log("yield - step - 3");
    40     }
    41 
    42     IEnumerator CountDown_WaitForFixedUpdate()
    43     {
    44         Debug.Log("yield WaitForFixedUpdate - step - 1");
    45         yield return new WaitForFixedUpdate();
    46         Debug.Log("yield WaitForFixedUpdate - step - 2");
    47         yield return new WaitForFixedUpdate();
    48         Debug.Log("yield WaitForFixedUpdate - step - 3");
    49     }
    50 
    51     IEnumerator CountDown_WaitForEndOfFrame()
    52     {
    53         Debug.Log("yield WaitForEndOfFrame - step - 1");
    54         yield return new WaitForEndOfFrame();
    55         Debug.Log("yield WaitForEndOfFrame - step - 2");
    56         yield return new WaitForEndOfFrame();
    57         Debug.Log("yield WaitForEndOfFrame - step - 3");
    58     }
    59 
    60     IEnumerator CountDown_WaitForSeconds()
    61     {
    62         Debug.Log("yield WaitForSeconds - step - 1");
    63         yield return new WaitForSeconds(1 / 60 * 3);//大概是三帧的时间
    64         Debug.Log("yield WaitForSeconds - step - 2");
    65         yield return new WaitForSeconds(1 / 60 * 3);
    66         Debug.Log("yield WaitForSeconds - step - 3");
    67     }
    68 }
    复制代码

    运行的结果如下,有点长,我就弄成两张图了:

    通过输出我们可以得出下面的结果:

    1. 当帧数波动时,FixedUpdate会进行多次补帧处理,我们可以发现两张图之间FixedUpdate从3一直补帧到15;
    2. WaitForFixedUpdate表示协程是跟在FixedUpdate之后执行的;
    3. WaitForEndOfFrame表示协程是跟在LateUpdate之后执行的;
    4. WaitForSeconds额。。。不用多说了,你指定多久后执行就多久后执行,当然由于是基于帧运算的,所以可能会不准确;

    最后补一张开头博客的运行顺序图:

    天道酬勤,功不唐捐!
  • 相关阅读:
    android29
    android28
    android27
    android26
    Dynamics CRM2011 MspInstallAction failed when installing an Update Rollup
    Dynamics CRM Import Solution Attribute Display Name description is null or empty
    The service cannot be activated because it does not support ASP.NET compatibility
    IIS部署WCF报 无法读取配置节“protocolMapping”,因为它缺少节声明
    Unable to access the IIS metabase.You do not have sufficient privilege
    LM算法与非线性最小二乘问题
  • 原文地址:https://www.cnblogs.com/lancidie/p/6085994.html
Copyright © 2011-2022 走看看