协同(Coroutine)
介绍
- 协同用来模拟线程,实现多任务。
- 在协同中可以使用等待语句。
什么情况下使用协同
在以下3种情况下可以使用协同:
- 当需要使用等待语句时,可以使用协同。
// 等待语句: yield return new WaitForSeconds(1.5f); //等待1.5秒 yield return null; // 等待一帧
- 当需要同时执行多个任务是,可以使用协同。
- 把一个大任务拆分成多个耗时不长的小任务。
协同的使用
使用协同需要3个步骤
- 定义协同函数。协同函数的返回值必须为
IEnumerator
。参数类型和个数可以任意。 - 在协同函数中使用等待语句。
- 启动协同。使用
StartCoroutine ()
方法调用协同函数。
// 协同的使用
private GameObject[] monsters;
private Transform startPoint;
private Transform monsterList;
void Start () {
// 开启协同
StartCoroutine (Wave ());
}
// 出一波怪
IEnumerator Wave() {
// 出10个怪
for (int i = 0; i < 10; i++) {
GenerateMonster ();
// 等待1.5秒
yield return new WaitForSeconds(1.5f);
}
}
void GenerateMonster() {
// 产生怪物
}
协同的嵌套
协同可以嵌套,在一个协同中可以启动另一个协同。
// 协同的嵌套
void Start () {
// 开启本关卡协同
StartCoroutine (Level ());
}
// 本关卡出怪逻辑
IEnumerator Level()
{
// 出3波怪
for (int i = 0; i < 3; i++) {
StartCoroutine(Wave ());
// 从出第一个怪开始,15秒后出下一波。
yield return new WaitForSeconds (15f);
}
}
// 出一波怪
IEnumerator Wave() {
// 出10个怪
for (int i = 0; i < 5; i++) {
GenerateMonster ();
// 等待1.5秒
yield return new WaitForSeconds(1.5f);
}
}
void GenerateMonster() {
// 产生怪物
}
对协同的理解
- Unity是单线程的。如下图,Unity会顺序的调用
Update
、协同
、LateUpdate
。 - Unity在每个
Update
之后检查有没有要执行的协同,如果有就调用协同。 - 协同函数使用
yield return
返回。当再次调用这个协同函数时,会从上次yield return
的地方继续执行,而不是从函数开始的地方从头执行。 - 协同用每一次
yield return
前执行代码的时间不要太长,这样会使后续的游戏GUI界面卡死。 当启动协同时会立马调用协同函数,因为给
StartCoroutine ()
传参时调用了协同函数。void Start () { StartCoroutine(FunCoroutine ()); } void Update () { Debug.Log ("Update"); } IEnumerator FunCoroutine () { // yield return null; while (true) { Debug.Log(“Coroutine”); yield return null; } }
运行结果如下:
对比生命周期图,解释为什么
yield return null;
表示等待一帧。- 对比生命周期图,说明一下这个结果。其中第一个Update之后发现协同在本轮中已经执行了,就不会再执行协同函数。
- 有些协同函数第一句代码就是
yield return null;
。这是为了跳过第一次协同函数的调用,保证协同函数一定在Update
之后执行。
相关应用Demo
- 等待3.5秒
(代码和注释)
- 等待一帧
(代码和注释)
- 等待10帧
(代码和注释)
- 等待条件成熟
// 可以将这句话理解为:当条件不成熟时一直等待。 (代码和注释)
- 加载场景等模块
(代码和注释)
相关参考
- 实现等待