目录
前言
学习来源:
一、什么是协程
二、协程的应用举例
三、协程的使用方式
3.1 启动
3.2 结束
3.3 嵌套
3.4 注意
四、Unity脚本的生命周期
五、yield速查表
前言
学习笔记,仅供学习,不做商用,如有侵权,联系我删除即可
学习来源:
Unity使用手册
Unity 协程(Coroutine)原理与用法详解https://blog.csdn.net/xinzhilinger/article/details/116240688?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168189731016800217270387%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168189731016800217270387&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-2-116240688-null-null.142%5Ev84%5Econtrol_2,239%5Ev2%5Einsert_chatgpt&utm_term=unity%E5%8D%8F%E7%A8%8B&spm=1018.2226.3001.4187
Unity-协程详解https://blog.csdn.net/qq_44705559/article/details/118052537
一、什么是协程
协程就像一个函数,能够暂停执行并将控制权返还给 Unity,然后在下一帧继续执行。
协程本质上是一个用返回类型 IEnumerator 声明的函数,并在主体中的某个位置包含 yield return 语句。
yield 的所在行是暂停执行并随后在下一帧恢复的点。
在 yield 语句之间可以正确保留任何变量或参数
默认情况下,协程将在执行 yield 后的帧上恢复,但也可以使用 WaitForSeconds 来引入时间延迟
注意:
协程不是多线程,它与主线程同时运行,它在主线程运行的同时开启另一段逻辑处理。
类似一个子线程单独出来处理一些问题,性能开销较小。
Unity的协程会在每帧结束之后去检测的条件是否满足,满足则执行yield return之后的代码。
二、协程的应用举例
以下来自 Unity Documentation手册 (V2020.1) 中的叙述:
游戏中的许多任务需要定期执行,最容易想到的方法是将任务包含在 Update 函数中。
但是,通常情况下,每秒将多次调用该函数。不需要以这样的频繁程度重复任务时,可以将其放在协程中来进行定期更新,而不是每一帧都更新。
这方面的一个示例可能是在附近有敌人时向玩家发出的警报。此代码可能如下所示:
function ProximityCheck()
{for (int i = 0; i < enemies.Length; i++){if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) {return true;}}return false;
}
如果有很多敌人,那么每帧都调用此函数可能会带来很大开销。但是,可以使用协程,每十分之一秒调用一次:
IEnumerator DoCheck()
{for(;;) {ProximityCheck();yield return new WaitForSeconds(.1f);}
}
这将大大减少所进行的检查次数,而不会对游戏运行过程产生任何明显影响。
三、协程的使用方式
3.1 启动
要将协程设置为运行状态,必须使用返回类型为 IEnumerator 声明的 StartCoroutine 函数
- StartCoroutine(string methodName):这种是没有参数的情况,直接通过方法名(字符串形式)来开启协程
- StartCoroutine(IEnumerator routine):通过方法形式调用
- StartCoroutine(string methodName,object values):带参数的通过方法名进行调用
3.2 结束
可以使用 StopCoroutine 和 StopAllCoroutines 来停止协程。 当用 SetActive(false) 禁用某个协程所附加到的游戏对象时,该协程也将停止。
调用 Destroy(example)
(其中 example
是一个 MonoBehaviour 实例)会立即触发 OnDisable
,并会处理协程,从而有效地停止协程。
最后,在帧的末尾调用 OnDestroy
。
通过在 MonoBehaviour 实例上将 enabled 设置为 false 来禁用 MonoBehaviour 时,协程不会停止。
StopCoroutine(string methodName)
:通过方法名(字符串)来进行StopCoroutine(IEnumerator routine):
通过方法形式来调用StopCoroutine(Coroutine routine)
:通过指定的协程来关闭
注意:
如果我们是使用StartCoroutine(string methodName)
来开启一个协程的
那么结束协程就只能使用StopCoroutine(string methodName)
和StopCoroutine(Coroutine routine)
来结束协程
3.3 嵌套
利用yield return StartCoroution(其它协程);
可以实现多个协程的嵌套使用。
3.4 注意
- IEnumerator 类型的方法不能带 ref 或者 out 型的参数,但可以带被传递的引用
- 在函数 Update 和 FixedUpdate 中不能使用 yield 语句,否则会报错, 但是可以启动协程
- 在一个协程中,StartCoroutine()和 yield return StartCoroutine()是不一样的。
- 前者仅仅是开始一个新的Coroutine,这个新的Coroutine和现有Coroutine并行执行。
- 后者是返回一个新的Coroutine,是一个中断指令,当这个新的Coroutine执行完毕后,才继承执行现有Coroutine。
四、Unity脚本的生命周期
根据生命周期图,当程序中设置协程时,程序的执行顺序为:(假设当前帧为第1帧)
- 第1帧在start中开启协程,执行协程(自上而下),执行到yield return行后,将后面的内容挂起。
- 这时继续执行第1帧剩下的东西直到第1帧Update执行结束。
- 在每一帧的update与lateupdate之间对挂起的内容进行判断,判断是否满足return条件。
- 若满足条件,则在第2帧的Update之后,在LateUpdate前,执行协程中yield return 以后的代码;
- 若不满足条件,则继续执行第1帧的LateUpdate。
第2帧的处理方法与第1帧相同。
五、yield速查表
yield语句 | 功能 |
---|---|
yield return null; | 下一帧再执行后续代码 |
yield return 0; | 下一帧再执行后续代码 |
yield return 6;(任意数字) | 下一帧再执行后续代码 |
yield break; | 直接结束该协程的后续操作 |
yield return asyncOperation; | 等异步操作结束后再执行后续代码 |
yield return StartCoroution(其它协程); | 调用执行其它协程后再执行后续代码 |
yield return abc(); | 等待abc操作完成后再执行后续代码 |
yield return new WaitForEndOfFrame(); | 等待帧结束,等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前执行 |
yield return new WaitForSeconds(0.1f); | 等待0.1秒,一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后(这里的时间会受到Time.timeScale的影响); |
yield return new WaitForSecondsRealtime(0.1f); | 等待0.1秒,一段指定的时间延迟之后继续执行,在所有的Update函数完成调用的那一帧之后(这里的时间不受到Time.timeScale的影响); |
yield return WaitForFixedUpdate(); | 等待下一次FixedUpdate开始时再执行后续代码 |
yield return new WaitUntil() | 将协同执行直到当输入的参数(或者委托)为true的时候 |
yield return new WaitWhile() | 将协同执行直到 当输入的参数(或者委托)为false的时候 |