Unity 协程用法总结
协程:协同程序,在主程序运行的同时,开启另外一段逻辑处理,来协同当前程序的执行,注意协程不是线程,只是具有线程特点的“伪协程”。
协程的使用需要直接或间接的继承MonoBehavior。
协程的执行原理
协程函数的返回值必须是IEnumerator,它是一个迭代器,可以把它当成执行一个序列的某个节点的指针,它提供了两个重要的接口,分别是Current(返回当前指向的元素)和MoveNext(将指针向后移动一个单位,如果移动成功,则返回true)。
yield关键词用来声明序列中的下一个值或是一个无意义的值,如果使用yield return x(x是指一个具体的对象或数值),那么MoveNext返回为true并且Current被赋值为x,如果使用yield break使得MoveNext()返回为false。
如果MoveNext函数返回为true意味着协程的执行条件被满足,则能够从当前的位置继续往下执行。否则不能从当前位置继续往下执行。
协同方法与普通方法的区别:
普通方法被调用时,原来执行的部分保留现场,停止执行,然后去执行要调用的方法,等待被调用的方法执行完之后才继续执行调用前的方法。
协同方法的执行是不用等协同方法执行完再执行调用之前原来方法的代码,即协程可暂停,两者异步执行。
开启协程的两种方式
1、StartCoroutine(string methodName) //参数为方法名字符串
2、StartCoroutine(IEnumerator method) //参数是方法名,方法中可包含多个参数
终止协程的两种方式:
StopCoroutine(string methodName) //只能终止以字符串形式启动的协程
StopAllCoroutine() //终止所有协程
协程的返回值
协程必须有有返回值,且返回值类型为IEnumrator。返回值语句为yield retuen 表达式或值 或 yield break。
yield:挂起,程序遇到yield关键字时会被挂起,暂停执行,等待条件满足时从当前位置继续执行
yield return 0 or yield return null: 程序在下一帧中从当前位置继续执行
yield return 1,2,3,…: 程序等待1,2,3…帧之后从当前位置继续执行
yield return new WaitForSeconds(float n): 程序等待n秒后从当前位置继续执行
yield return WWW: 等待一个网络请求完成后从当前位置继续执行
yield return StartCoroutine(): 等待一个协程执行完成后从当前位置继续执行
yield new WaitForEndOfFrame(): 在所有的渲染以及GUI程序执行完成后从当前位置继续执行
yield new WaitForFixedUpdate(): 所有脚本中的FixedUpdate()函数都被执行后从当前位置继续执行
yield break:协程执行条件不满足,即不会从当前的位置继续执行协程,将回到函数继续执行。
协程的一些注意地方:
- 多个协程可以同时运行,它们会根据各自的启动顺序来更新;
- 协程可以嵌套任意多层;
- 如果你想让多个脚本访问一个协程,那么你可以定义静态的协程;
- 如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们;
- IEnumerator类型的方法不能带ref或者out型的参数,但可以带被传递的引用;
- 目前在Unity中不能检测作用于对象的协程数量以及具体是哪些协程作用在对象上。
协程简单实例
- 运动到某一位置
对于下面这个简单脚本组件,我们可以在Inspector面板中给targetPosition和moveSpeed变量赋值,程序运行的时候,该对象就会在协程的作用下,以我们给定的速度运动到给定的位置。
usingUnityEngine;
Using System.Collections;
Public class MoveExample : MonoBehaviour
{
public Vector3 targetPosition;
public float moveSpeed;
Void Start()
{
StartCoroutine(MoveToPosition(targetPosition));
}
IEnumerator MoveToPosition(Vector3 target)
{
while(transform.position != target)
{
transform.position = Vector3.MoveTowards(transform.position, target, moveSpeed * Time.deltaTime);
Yield return 0;
}
}
}
- 按指定路径前进
我们可以让运动到某一位置的程序做更多,不仅仅是一个指定位置,我们还可以通过数组来给它赋值更多的位置,通过MoveToPosition() ,我们可以让它在这些点之间持续运动。
Using UnityEngine;
Using System.Collections;
Public class MoveExample : MonoBehaviour
{
public Vector3[] path;
public float moveSpeed;
Void Start()
{
StartCoroutine(MoveOnPath(true));
}
IEnumerator MoveOnPath(bool loop)
{
do
{
foreach(var point in path)
Yield return StartCoroutine(MoveToPosition(point));
}
while(loop);
}
IEnumerator MoveToPosition(Vector3 target)
{
while(transform.position != target)
{
transform.position = Vector3.MoveTowards(transform.position, target, moveSpeed * Time.deltaTime);
Yield return 0;
}
}
}