通过unity协程调度器来开启协程,yield return后面逻辑的执行时机如下
yield return不同内容的含义
1.下一帧执行
yield return 数字;
yield return null;
//在update和LateUpdate之间执行
2.等待指定秒过后执行
Yield return new WaitforSecends(秒):
//在update和LateUpdate之间执行
3.等待下一个固定物理帧更新时执行
Yeild return WaitForFixedUpdate();
//在FixedUpdate和碰撞相关函数之后执行
4.等待摄像机和GUI渲染过后执行
Yield return new WaitForEndOfFrame();
//在LateUpdate之后的渲染相关处理完毕后
主要用于做截图功能时
5.一些特殊类型的对象,比如异步加载相关函数返回的对象
//一般在Update和LateUpdate之间执行
6.跳出协程
Yield return;
此时我利用c#迭代器和unity生命周期函数来实现自己的协程调度器,让yield return 数字,表示等待多少秒执行后面的逻辑。也就是实现 new WaitforSecends(秒)类的功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class YiedlReturnTime
{
//记录 下次还要执行的 迭代器接口
public IEnumerator e;
//记录 下次执行的时间
public float time;
}
public class CoroutineMrg : MonoBehaviour
{
//单例模式
private static CoroutineMrg instance;
public static CoroutineMrg Instance => instance;
//存储迭代器函数对象的容器
//因为可以在不同的地方通过该协程调度器来开启协程(同时可以开启多个协程)
private List<YiedlReturnTime> list = new List<YiedlReturnTime>();
void Start()
{
instance = this;
}
void Update()
{
//为了避免在循环的过程移除元素而导致元素位置改变,需要从列表中移除内容 我们可以倒着遍历
for(int i=list.Count-1;i>=0;i--)
{
//判断 当前迭代器函数 是否到了下一次执行的时间
if(list[i].time<=Time.time)
{
if(list[i].e.MoveNext())
{
//如果是true 那还需要对该迭代器 进行处理
if(list[i].e.Current is int)
{
list[i].time = Time.time + (int)list[i].e.Current;
}
else
{
//该list 只是存储 处理时间相关 等待逻辑的 迭代器函数
//如果是别的类型就因该存储到别的容器中
}
}
else
{
//后面已经没有可以等待和执行的了 证明已经执行完毕了逻辑。
list.RemoveAt(i);
}
}
}
}
public void MystartCoroutine(IEnumerator e)
{
//传入一个 迭代器函数返回的结构,那么一来就因该执行它
//一来就执行第一步
if(e.MoveNext())
{
//如果yield return 返回的是数字
if(e.Current is int)
{
//按思路 应该把 这个迭代器函数 和它下一次执行的时间点 记录下来
//然后不停检测 时间 是否达到了 下一次执行的时间点
YiedlReturnTime y = new YiedlReturnTime();
y.e = e;
y.time = Time.time + (int)e.Current;
//把记录的信息记录到数据容器中
list.Add(y);
}
else
{
//其它类型代表的意思 需要自行实现
}
}
}
}
测试类
using System.Collections;
using UnityEngine;
public class Lession15 : MonoBehaviour
{
IEnumerator MyCoroutine()
{
print("第1次");
yield return 1;//等待1秒
print("第2次");
yield return 10;//等待10秒
print("第3次");
}
void Start()
{
//利用自己实现的协程调度器 来 开启协程
CoroutineMrg.Instance.MystartCoroutine(MyCoroutine());
}
}
注意:两个类都要挂载到游戏物体上,查看截图时间,分别等待了1秒和10秒。