协程概念理解与应用
一、协程概念理解
- 与方法一样,协程也是一种程序组件。
- 相对于一般方法而言,协程更为灵活,方法只有一个入口,而协程可以有多个入口和出口点,可以用协程来实现任何的方法。
- 协程更适合用于实现如合作式多任务,迭代器,无限列表。
例如:在update方法当中,需要遍历1000次,在普通方法当中就需要一帧完成遍历1000次,而用协程可以分多次来做。 - 开始一个协程时,执行从被调用方法的起始处开始;然而,接下来的每次协程被调用时,从协程返回(yield return)的位置接着执行。
- 协程是单线程的。
二、Unity中协程实现
- Unity协程实现主要组成:
– IEnumerator接口 提供迭代
– yield return xxxx 指定下一次迭代入口
WaitForFixedUpdate在FixedUpdate后执行,适用于物理控制
null、0、WatiForSeconds在每帧Update后执行,适用于分分多帧完成一个任务,如A*路径计算
WaitForEndOfFrame在每帧结束后执行,适合于每帧末尾执行的操作,如相机控制
WWW 在请求结束后执行,适合于网络下载数据 - StartCoroutine 开启协程
- 生命周期如下:
- IEnumerator与协程同时使用,否则会报错
private IEnumerator Start(){
yield return new WaitForSeconds(1);
print("第一次输出");
yield return new WaitForSeconds(2);
print("第二次输出");
yield return new WaitForSeconds(3);
print("第三次输出");
}
在unity中运行,观察控制台结果,可发现输出的结果并不是在一帧中完成的。
- 若是在自定义方法当中使用协程,则在调用该方法时需要使用StartCoroutine()来调用协程方法
- 在Update、FixUpdate等类似方法当中不能使用协程,但是可以调用协程方法。
三、协程的停止
- StopCoroutine(string)
– StopCoroutine(“协程方法名”)
– 只能停止以StartCoroutine(“协程方法名”)开启的协程(只能停止以字符串形式开启的) - StopAllCoroutine()
–停止本对象中开启的所有协程
四、使用协程的注意
- 在程序中调用StopCoroutine()方法只能终止以字符串形式开启的协程
- 多个协程可以同时运行,它们会根据各自的启动顺序来更新
- 协程可以嵌套任意多层
- 如果你想让多个脚本访问一个协程,那么你可以定义静态的协程。
- 协程不是多线程,它们运行在同一线程中,跟普通的脚本一样。
- 如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们
- IEnumerator类型的方法不能带ref或者out型的参数
- 目前在Unity中没有简便的方法来检测作用于对象的协程数量以及具体是哪些协程作用在对象上
五、协程的应用案例
让物体按指定路径进行前进,在每到一个路径节点可让其等待几秒再进行前进,类似如此,可制作人物的巡逻模式。
测试代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ForwardCube : MonoBehaviour
{
public int speed = 5;
public Transform[] points;
private void Start()
{
}
private void OnGUI()
{
if (GUILayout.Button("开始巡逻"))
{
StartCoroutine(FindPointToMove());
}
}
/// <summary>
/// 向给定路径节点进行前进
/// </summary>
/// <returns></returns>
private IEnumerator Move(Vector3 target)
{
while (this.transform.position!=target)
{
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
yield return new WaitForFixedUpdate();
}
}
private IEnumerator FindPointToMove()
{
foreach (Transform target in points)
{
StartCoroutine(Move(target.position));
yield return new WaitForSeconds(3);
}
}
}