关于Unity中协程的些许思考

1.什么是协程?


从字面意思来理解,可以是:协助主程序的程序;比较官方一点的解释是:在主程序执行时,开辟一段逻辑处理

2.在Unity中协程的用法


使用协程分两步:

-     通过StartCorutine调用协程的逻辑方法
-     完善协程的逻辑方法,返回值是IEnumrator,通过关键字yield来实现

StarCorotine Demo:

    
    void Awake()
    {
    StartCoroutine(SayHello());
    }
    
    private IEnumerator SayHello()
    {
    for (int i = 0; i < 10; i++)
    {
    Debug.Log("逻辑处理片段....begin");
    Debug.Log("current unit :..............." + i);
    yield return 2.0f;
    Debug.Log("逻辑处理片段....end");
    }
    }

3.协程的实现原理: 


协程其实是单线程下的异步处理, 只是让程序看起来是异步的;通常的应用场景有,进入场景的加载页面,事件的延时操作等(欢迎补充...)

协程的实现基于C#中的迭代器,具体关于C#迭代器的介绍可以访问:


C#迭代器

StartCorotine其实是启动一个事件,这个事件可以是Mono默认的事件,也可以是我们自己定义的;
而yield return 其实是返回这个事件的执行节点(通俗说,就是事件在哪暂停了);

具体关于Unity默认的中断协程的,将在文后进行总结.





4.关于Unity 自定义 协程事件


在C#脚本中,我们可以看到StartCorotine的参数是一个IEnumerator,而IEnumrator有什么用呢?通过阅读IEnumrator接口和查阅相关资料,并结合Unity的脚本生命周期:   Unity脚本生命周期

我得出了一个大概的过程:根据在调用Update的上下文每次都会去调用yield return,而在yield return之前必执行我们协程逻辑函数里面的代码,所以,可以知道,我们开启协程之后,每帧都会调用我们的协程逻辑函数,但是它每帧都是从上一个协程中断节点(也就是yield return)处开始执行,直到逻辑函数执行完毕。

另外,有一点需要注意的是:StartCorotine的返回值是Coroutine,Coroutine继承了YieldInstruction,巧合的是yield return 后面的返回值,比如WaitForSceconds也继承了YieldInstruction,因此我猜测,yield return 后面的返回值对象应该和Corotine存在某种联系,而在我看过Unity官方文档之后,有一点点释然了: Unity自定义协程返回事件

事实上,这个YieldInstruction是IEnumrator的子类,姑且先这样认为.从文档中,可以了解到如果我们要写自定义协程事件,可以选择继承CustomYieldInstruction,也可以采用继承IEnumrator的方式都可以.也因此我认为CustomYieldInstruction是对IEnumrator的一层封装,单着仅仅是我个人猜测;这样,就可以理解为什么协程是基于迭代器的了;但是Corotine和yield return 存在什么联系,可能是Corotine需要IEnumrator来进行枚举,然而yield return 是提供IEnumrator进行枚举;或许是这种原因,如果说他们之间存在什么转换关系,可能就不得而知了。

5.Unity 中默认的 yield return 事件

yield WaitForFixedUpdate
yield null
yield WaitForSeconds
yield WWW
yield StartCorotine
yield WaitForEndOfFrame

上面这些其实很好理解,我觉得需要注意一下顺序即可.
yield WaitForFixedUpdate:Update之前

yield null:Update之后,下一帧执行
yield WaitForSeconds: 等待固定时间执行
yield StartCorotine: 等待另一个协程执行完毕
yield WaitForEndOfFrame:用于截屏
yield WaitUntil:等待委托Func<bool>返回为true时,执行下面的Code;在Update之后和LateUpdate之间调用.
    using UnityEngine;
    using System.Collections;
    
    public class WaitUntilExample : MonoBehaviour
    {
    public int frame;
    
    void Start()
    {
    StartCoroutine(Example());
    }
    
    IEnumerator Example()
    {
    Debug.Log("Waiting for princess to be rescued...");
    yield return new WaitUntil(() => frame >= 10);
    Debug.Log("Princess was rescued!");
    }
    
    void Update()
    {
    if (frame <= 10)
    {
    Debug.Log("Frame: " + frame);
    frame++;
    }
    }
    }
yield WaitWhile:等待委托Func<bool>返回为false时,执行下面的Code;在Update之后和LateUpdate之间调用.
    using UnityEngine;
    using System.Collections;
    
    public class WaitWhileExample : MonoBehaviour
    {
    public int frame;
    
    void Start()
    {
    StartCoroutine(Example());
    }
    
    IEnumerator Example()
    {
    Debug.Log("Waiting for prince/princess to rescue me...");
    yield return new WaitWhile(() => frame < 10);
    Debug.Log("Finally I have been rescued!");
    }
    
    void Update()
    {
    if (frame <= 10)
    {
    Debug.Log("Frame: " + frame);
    frame++;
    }
    }
    }

6.自定义yieldreturn事件

 yield return 的返回值,我们可以根据自己需求来定义协程何时被继续执行;必须继承抽象类CustomYieldInstruction,实现KeepWaiting的Get方法.

   using System.Collections;
    using UnityEngine;
    
    public class ExampleScript : MonoBehaviour
    {
    void Update()
    {
    if (Input.GetMouseButtonUp(0))
    {
    Debug.Log("Left mouse button up");
    StartCoroutine(waitForMouseDown());
    }
    }
    
    public IEnumerator waitForMouseDown()
    {
    yield return new WaitForMouseDown();
    Debug.Log("Right mouse button pressed");
    }
    }
 自定义:YieldInstruction
    using UnityEngine;
    
    public class WaitForMouseDown : CustomYieldInstruction
    {
    public override bool keepWaiting
    {
    get
    {
    return !Input.GetMouseButtonDown(1);
    }
    }
    
    public WaitForMouseDown()
    {
    Debug.Log("Waiting for Mouse right button down");
    }
    }

猜你喜欢

转载自blog.csdn.net/ye_wolf/article/details/79479370