Unity 协程
🌀 Unity 协程(Coroutine)
- 协程(Coroutine):Unity 提供的一种“分时执行”机制,本质上不是多线程,而是在主线程上分步执行代码,避免卡顿。
- 适用场景:
- 异步加载资源或场景
- 批量生成对象
- 流程控制(动画、等待、定时器等)
- 异步操作(网络请求、下载)
1. 协程的本质
- 协程分为两部分:
- 协程函数本体:利用 C# 的迭代器函数(
IEnumerator+yield return)实现“分布执行”,可以把函数逻辑拆成多段依次执行。 - 协程调度器:Unity 内部实现,用于管理协程函数的执行时机,决定何时继续执行迭代器的下一段。
- 协程函数本体:利用 C# 的迭代器函数(
- 核心理解:
- 迭代器函数的
MoveNext()方法可以遍历函数中各段逻辑,实现分时执行。 - 协程调度器根据
yield return返回的内容来决定下一步执行的时机。
- 迭代器函数的
- 理论上,我们可以用迭代器函数自己实现调度器,替代 Unity 的协程调度器。
2. 协程 基本用法
协程函数必须满足两个条件:
- 返回值为
IEnumerator或继承类型 - 函数内部使用
yield return返回值
| 写法 | 含义 |
|---|---|
yield return null |
下一帧继续执行 |
yield return new WaitForSeconds(seconds) |
等待指定秒数后执行 |
yield return new WaitForFixedUpdate() |
等待下一帧物理更新 |
yield return new WaitForEndOfFrame() |
等待摄像机和GUI渲染完成后执行 |
yield break |
退出协程 |
public class Test : MonoBehaviour
{
void Start()
{
// 开启协程函数
Coroutine c1 = StartCoroutine(MyCoroutine(1, "Hello"));
Coroutine c2 = StartCoroutine(MyCoroutine(2, "World"));
// 关闭协程函数
StopCoroutine(c1); // 一. 关闭指定协程
StopAllCoroutines(); // 二. 关闭所有协程
}
// 定义协程逻辑
IEnumerator MyCoroutine(int i, string str)
{
print(i);
yield return null; // 下一帧执行
print(str);
yield return new WaitForSeconds(1f); // 等待 1 秒
print("After 1 second");
yield return new WaitForFixedUpdate(); // 等待下一帧物理更新
print("After FixedUpdate");
yield return new WaitForEndOfFrame(); // 等待渲染完成
print("After EndOfFrame");
// 可以循环执行
while(true)
{
print("Looping every 1 second");
yield return new WaitForSeconds(1f);
}
}
}
注意:
- 协程绑定在
MonoBehaviour上,如果对象或组件被销毁或失活,协程会自动停止执行。- 协程本质是迭代器函数 + 调度器,并不是多线程,因此可以安全访问 Unity API,但不能阻塞主线程。
3. 自定义协程
- 实现了按自己定的规则来执行逻辑:return的值就是等待多少秒
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Exercise7 : MonoBehaviour
{
IEnumerator ie;
IEnumerator MyCoroutine()
{
print("1");
yield return 1;
print("2");
yield return 2;
print("3");
yield return 3;
print("4");
yield return 4;
print("5");
yield return 5;
print("6");
}
void Start()
{
ie = MyCoroutine();
CoroutineMgr.Instance.MyStartCoroutine(ie);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class YieldReturnTime
{
//记录 下次还要执行的 迭代器接口
public IEnumerator ie;
//记录 下次执行的时间点
public float time;
}
class CoroutineMgr : MonoBehaviour
{
private static CoroutineMgr instance;
public static CoroutineMgr Instance => instance;
//int时间类型协程迭代器
private List<YieldReturnTime> list = new List<YieldReturnTime>();
private void Awake()
{
instance = this;
}
//执行首次协程,加入迭代器列表
public void MyStartCoroutine(IEnumerator ie)
{
if (ie.MoveNext())
{
if (ie.Current is int)
{
YieldReturnTime y = new YieldReturnTime();
y.ie = ie;
y.time = Time.time + (int)ie.Current;
list.Add(y);
}
}
}
private void Update()
{
for (int i = list.Count - 1; i >= 0; i--)
{
//判断 当前该迭代器函数 是否到了下一次要执行的时间
//如果到了 就需要执行下一步了
if (list[i].time <= Time.time)
{
if (list[i].ie.MoveNext())
{
//如果过是true 那还需要对该迭代器函数进行处理
if (list[i].ie.Current is int)
{
list[i].time = Time.time + (int)list[i].ie.Current;
}
else
{
//该list 只是存储 处理时间相关 等待逻辑的 迭代器函数的
//如果是别的类型 就不应该 存在这个list中 应该根据类型把它放入别的容器中
list.RemoveAt(i);
}
}
else
{
//后面已经没有可以等待和执行的了 证明已经执行完毕了逻辑
list.RemoveAt(i);
}
}
}
}
}

浙公网安备 33010602011771号