勇哥注:
协程是字面意思,就是协作关系的代码。
用过之后感觉跟C#的async await很像,也就是异步。
但根据一些资料可以知道,对于脚本代码的执行,unity是使用的单线程的。
因此它的这个协程并不是多线程,它究竟是个什么原理,是比较有意思的话题。
协程的作用:
任何的程序代码和逻辑处理都是按照顺序执行的。
协程就是开启一段和主程序异步执行的逻辑处理。
但是我们的代码并不是同时执行的。
协程会通过我们不同的yield指令把我们的代码穿插在我们的代码的生命周期中。
yield指令都有些什么呢?后面会介绍。
(一)我们先了解开启和关闭协程。
特点是:IEnumberator 开头,并且函数体中有一句yield;
下面是协程方法和普通方法的对比:
IEnumberator PrintNum()
{
Debug.Log(2);
Debug.Log(3);
yield return 0;
}
void PrintNum()
{
Debug.Log(2);
Debug.Log(3);
}
当运行到 yield return 0; 这一行时,就会把程序暂时挂起。
当我们满足一个特定的条件时,才会继续执行我们剩下的代码。
调用协程函数是不能这样:
PrintNum();
而是要这样:
StartCoroutine(PrintNum());
(二)关闭协程
StopCoroutine(PrintNum());
StopAllCoroutines(); //关闭全部协程
(三)详细了解yield
IEnumberator PrintNum()
{
Debug.Log(1);
yield return 0;
Debug.Log(2);
}
void Start()
{
StartCoroutine(PrintNum());
Debug.Log(3);
}
这里代码 yield return 0; 作用就是在执行它时把程序挂起,并在这一帧的Update()执行后,再执行我们剩下的代码。
这里的执行顺序会变成:1--3--2
如果上面的协程是个普通函数,执行顺序则是:1--2--3
yield return 0;改成 yield return null; 效果是完全一样的。
其它的yield用法:
(1)WaitForSeconds(1);
yield return new WaitForSeconds(1);
执行这句时,程序挂起到指定秒,再执行后面的语句。
这里指定的秒数是受 Time.timeScale 影响的。
因此还有一种不受它影响的方式:
yield return new WaitForSecondsRealtime(1);
(2) WaitForFixedUpdate();
yield return new WaitForFixedUpdate();
执行这句时,程序挂起,等待所有的物理运算完成后再执行后面的语句。
FixedUpdate()函数就是给我们物理运算的。
(3)WaitForEndOfFrame();
执行这句时,程序挂起,等待这一帧所有的代码都运行完(包括Update(),FiexedUpdate()和我们的GUI渲染),再执行后面的代码。
兴几个粟子
(1)按顺序执行轴动作
下面程序用来移动Cube, 沿矩形路径移动。也就是移动了4个点位。
源码:
运行后点击Cube对象,启动工作协程。
using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEngine; public class yieldTest : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } private void OnMouseDown() { Debug.Log("click..."); StartCoroutine(Working()); } IEnumerator Working() { yield return StartCoroutine("Move1"); yield return StartCoroutine("Move2"); yield return StartCoroutine("Move3"); yield return StartCoroutine("Move4"); } float distance = 0.01f; IEnumerator Move1() { Debug.Log("forward..."); for (int i = 0; i < 160; i++) { transform.Translate(Vector3.forward* distance); yield return new WaitForSecondsRealtime(2 / 60); } } IEnumerator Move2() { Debug.Log("right..."); for (int i = 0; i < 160; i++) { transform.Translate(Vector3.right * distance); yield return new WaitForSecondsRealtime(2 / 60); } } IEnumerator Move3() { Debug.Log("back..."); for (int i = 0; i < 160; i++) { transform.Translate(Vector3.back * distance); yield return new WaitForSecondsRealtime(2 / 60); } } IEnumerator Move4() { Debug.Log("left..."); for (int i = 0; i < 160; i++) { transform.Translate(Vector3.left * distance); yield return new WaitForSecondsRealtime(2 / 60); } } }
其它资料
有一篇B站的视频对协程讲解很到位,各位可以深入了解下。

