U3D协程yield的使用和理解

部分内容参考网址:http://blog.csdn.net/huang9012/article/details/29595747

Win7+U3D 4.6.7

Win10 + U3D2023.1

1.在c#中使用
①首选需要定义一个返回值为IEnumerator的协程函数

1 IEnumerator Do(){
2     Debug.Log("Do 1");
3 
4     yield return 0; //下面的代码延时到下一帧的update之后
5 
6     Debug.Log("Do 2");
7 }

 

②使用StartCoroutine函数调用协程函数

1     void Start () {
2         Debug.Log("Start 1");
3         StartCoroutine(Do()); //调用协程函数
4         Debug.Log("Start 2");
5     }

③在Update函数中输出数字,判断Updata函数和协程之间的执行先后顺序

1 int i = 0;
2 void Update () {
3     ++i;
4     Debug.Log("Update " +i); //这里记录了调用update函数多少次
5 }

④在LateUpdate函数中输出数字,判断LateUpdate函数和协程之间的执行先后顺序

1 int j = 0;
2 void LateUpdate()
3 {
4     ++j;
5     Debug.Log("LateUpdate " + j); //这里记录了调用update函数多少次
6 }

⑤运行的输出顺序结果是:

 1 Start 1
 2 Do 1 //yield之后再下一帧的update之后继续执行
 3 Start 2
 4 Update 1//第一帧(当前帧)update执行完
 5 LateUpdate 1//第一帧(当前帧)的最后执行
 6 Update 2//第二帧(下一帧执行)update执行完
 7 Do 2//执行yield之后的代码
 8 LateUpdate 2//没错,LateUpdate在协程之后
 9 Update 3
10 LateUpdate 3
11 Update 4
12 LateUpdate 4
13 Update 5
14 LateUpdate 5

 

2.关于启停

①通过函数名字字符串启停

StartCoroutine("Do");
StopCoroutine("Do");

②通过函数对象启停

IEnumerator d= Do();
StartCoroutine(d);
StopCoroutine(d);

//需要注意,下面的代码不能停止

StartCoroutine(Do());
StopCoroutine(Do());

③停止所有

StopAllCoroutines();

 

3.关于协程的理解:

①在传统实时游戏中,在update中要延迟执行一些代码,或者满足一定条件后执行一些代码。需要在update添加一个计时器,用当前时间来减去前面记录的时间来判断执行。当这种情况越来越多的时候,会添加很多变量和代码,代码就越来越乱,这时候一般会抽象一个框架出来处理这个问题。协程就是解决这种问题的框架,换句话说yield return 0(return的是int值,任何值都一样,没有区别)的作用,就是在调用yield那行代码后(在yield函数处做一个记录标签),然后跳出协程函数继续执行外部的代码,在下一帧(是下一帧!)的update函数之后,根据yield函数的记录标签位置继续执行协程函数的后面部分代码。

yield return int/null是等待下一帧(应用场景:倒计时,分数累加,血条慢慢减少等)
yield return new WaitForSeconds (2)是等待时间到
yield return new WWW(“http://pcwen.top”)是等到页面响应
③协程和Update()一样更新,自然可以使用Time.deltaTime了,而且这个Time.deltaTime和在Update()当中使用是一样的效果(使用yield return int的情况下)
④协程并不是多线程,它和Update()一样是在主线程中执行的,所以不需要处理线程的同步与互斥问题 

 

4.为了更清楚的说明yield return int的下一帧执行的用处,分别使用两种方法实现同一个延时功能。
①使用update不断累加时间

 1 using UnityEngine;
 2 using System.Collections;
 3   
 4   public class dialog_easy : MonoBehaviour {
 5       public string dialogStr = "一个一个字显示";
 6       public float speed = 5.0f;
 7   
 8       private float timeSum = 0.0f;
 9      private bool isShowing = false;
10      // Use this for initialization
11      void Start () {
12          ShowDialog();
13      }
14      
15      // Update is called once per frame
16      void Update () {
17          if(isShowing){
18              timeSum += speed * Time.deltaTime;
19              guiText.text = dialogStr.Substring(0, System.Convert.ToInt32(timeSum));
20  
21              if(guiText.text.Length == dialogStr.Length)
22                  isShowing = false;
23          }
24      }
25  
26      void ShowDialog(){
27          isShowing = true;
28          timeSum = 0.0f;
29      }
30 }

②使用yield return int每帧自动调用(明显这种用法简洁明了得多)

 1 using UnityEngine;
 2   using System.Collections;
 3   
 4   public class dialog_yield : MonoBehaviour {
 5       public string dialogStr = "一个一个字显示";
 6       public float speed = 5.0f;
 7   
 8       // Use this for initialization
 9       void Start () {
10          StartCoroutine(ShowDialog());
11      }
12      
13      // Update is called once per frame
14      void Update () {
15      }
16      
17      IEnumerator ShowDialog(){
18          float timeSum = 0.0f;
19          while(guiText.text.Length < dialogStr.Length){
20              timeSum += speed * Time.deltaTime;
21              guiText.text = dialogStr.Substring(0, System.Convert.ToInt32(timeSum));
22              yield return null;
23          }
24      }
25 }

 

posted @ 2016-08-07 03:37  pcwen.top  阅读(1354)  评论(0编辑  收藏  举报
pcwen.top