Unity中的协程是模拟操作系统线程的(名称很相近),使用的感觉也相近。不同之处是:线程是操作系统管理的,而协程是Unity管理并运行在主线程中(每帧运行一次,每秒运行30或60次);
协程的优势
协程的使用方便且强大,在游戏编程中很常见。游戏编程的很多逻辑需要跨帧才能完成(尤其涉及到动画表现相关的逻辑),在不用协程的情况下,可能需要在Update的逻辑中进行(其中逻辑状态需要存放为类变量);而改用协程,代码就会变得很简单,且状态只需要维护为方法变量;举例:
1)Update的方法:
public class MyAnim1 : MonoBehaviour {
public Vector3 startPos, endPos;
public float speed;
// 状态
private float progress;
void Start () {
progress = 0;
}
void Update () {
progress += Time.deltaTime * speed;
transform.position = Vector3.Lerp(startPos, endPos, progress);
}
}
2)用协程的方法:
public class MyAnim2 : MonoBehaviour {
public Vector3 startPos, endPos;
public float speed;
void Start() {
StartCoroutine(doAnim()); // 启动协程
}
private IEnumerator doAnim() {
var progress = 0f; // 状态
while (true) {
yield return null; // 等待一帧
progress += Time.deltaTime * speed;
transform.position = Vector3.Lerp(startPos, endPos, progress);
}
}
}
这个例子虽然简单,但是Update的方法的progress的维护要分散在代码的3处,而协程就在一个方法内,这就体现了协程的优势;如果动画有多个的话,使用协程的方便性和可维护性就会更加明显。
Unity的协程管理
Unity管理协程的方式基于两点:1)游戏引擎每秒更新30帧(或则60帧等);2)C#语言对协程的支持;
自己管理协程
在游戏开发中,有些时候需要自己管理协程。运用场景举例:
1)一些帧同步的网游,驱动逻辑更新的源头是网络上过来的“逻辑帧”(非游戏刷新帧),网络上每到来一“逻辑帧”,逻辑就需要更新一次(帧同步频率一般会低于游戏刷新帧---比如帧同步频率是15帧/秒。但由于网络卡顿延迟,会把延后“逻辑帧”积累起来一起发送,这样游戏的一个刷新帧内会到来多个“逻辑帧”)。
2)自己想用协程的方式来管理一些游戏功能,比如状态机的简化处理等(以后有时间会写一些相关文章);
在项目中,有的时候需要手动控制协程的更新,也就是重写StartCoroutine方法。具体如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
public class CoroutineManager {
public Clock clock { get; private set; }
private HashSet<CoroutineIter> cIters ;
private List<CoroutineIter> itAddTemp;
private List<CoroutineIter> itDelTemp;
private CoroutineManager() {
cIters = new HashSet<CoroutineIter>();
itAddTemp = new List<CoroutineIter>();
itDelTemp = new List<Cor