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#迭代器的介绍可以访问:
而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");
}
}