Unity中自定义协程的简单实现

打印 上一主题 下一主题

主题 1005|帖子 1005|积分 3017

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在 Unity 中,协程(Coroutine)是一种非常强盛的工具,它允许我们在不壅闭主线程的情况下,将代码的实行分成多个步调,在不同的帧中实行。
Unity中协程实现原理
迭代器与状态机:本质上是基于C#的迭代器和状态机实现的。迭代器允许函数暂停和规复实行,协程函数使用 yield return 语句暂停,保存当前状态,下次被调用时从暂停处继续。Unity在底层通过状态机管理协程状态,记录实行位置和局部变量等。
消息循环与时间管理:Unity的消息循环在每一帧查抄协程状态。当协程 yield return 一个条件或等待时间时,Unity记录该条件,在后续帧中查抄条件是否满足,满足则规复协程实行。
实行队列与调理:Unity维护协程实行队列,按添加顺序或优先级调理协程。协程加入队列后,等待Unity根据帧循环和条件判断调理实行。
要实现自定义协程需用到一个暂停指令和协程的MoveNext方法:
1.YieldInstruction:用于实现协程的暂停指令,所有详细的暂停指令都需要继续自该类,并实现IsDone方法,用于判断暂停是否完成。
2.MoveNext方法:通过不停调用该方法,检测协程的暂停条件是否成立,假如条件成立,协程从暂停处继续实行,否则协程不会继续实行。
定义一个暂停指令基类:
  1. public abstract class YieldInstruction
  2. {
  3.     public abstract bool IsDone();
  4. }
复制代码
定义一个暂停指令:重写IsDone函数
  1. public class WaitForFrames : YieldInstruction
  2. {
  3.     public override bool IsDone()
  4.     {
  5.         remainingFrames--;
  6.         return remainingFrames <= 0;
  7.     }
  8. }
复制代码
 自定义一个协程类:它需要包含暂停指令、需要实行的迭代器函数、还要实现一个MoveNext函数,详细实现如下:
  1.     public bool MoveNext()
  2.     {
  3.         //首先判断暂停指令是否存在
  4.         if (currentYield != null)
  5.         {
  6.             if (!currentYield.IsDone())
  7.             {
  8.                 // 当前 YieldInstruction 未完成,继续等待
  9.                 return true;
  10.             }
  11.             // 当前 YieldInstruction 完成,重置
  12.             currentYield = null;
  13.         }
  14.         //如果迭代器的MovenNext方法返回true则协程等待
  15.         if (routine.MoveNext())
  16.         {
  17.             currentYield = routine.Current as YieldInstruction;
  18.             return true;
  19.         }
  20.         // 协程执行完毕
  21.         return false;
  22.     }
复制代码
自定义调理器: 需要实现StartCoroutine,StopCoroutine和Update函数
  1.     // 存储待执行的协程列表
  2.     private List<CustomCoroutine> coroutines = new List<CustomCoroutine>();
  3.     // 启动一个协程
  4.     public CustomCoroutine StartCoroutine(IEnumerator routine)
  5.     {
  6.         CustomCoroutine coroutine = new CustomCoroutine(routine);
  7.         coroutines.Add(coroutine);
  8.         return coroutine;
  9.     }
  10.     // 更新协程调度器,需要在每一帧调用
  11.     public void Update()
  12.     {
  13.         for (int i = coroutines.Count - 1; i >= 0; i--)
  14.         {
  15.             coroutines[i].MoveNext();
  16.         }
  17.     }
  18.     public void StopCoroutine(CustomCoroutine routine)
  19.     {
  20.         coroutines.Remove(routine);
  21.     }
  22.     public void StopAllCoroutine()
  23.     {
  24.         coroutines.Clear();
  25.     }
复制代码
调用:
  1.     CustomCoroutineScheduler scheduler = new CustomCoroutineScheduler();
  2.     void Start()
  3.     {
  4.         // 启动一个协程
  5.         scheduler.StartCoroutine(TestCoroutine());
  6.     }
  7.     void Update()
  8.     {
  9.         scheduler.Update();
  10.     }
  11.     IEnumerator TestCoroutine()
  12.     {
  13.         Debug.Log("Coroutine started");
  14.         yield return new WaitForFrames(3);
  15.         Debug.Log("Waited for 3 frames");
  16.         Debug.Log("Coroutine ended");
  17.     }
复制代码
 结果:

其他有用的链接:
KarnageUnity/CustomCoroutine: Two C# classes demonstrating how Unity implements Coroutines (github.com)
gohbiscuit/UnityCustomCoroutine: Unity Custom Coroutine class can be use to handle multiple or nested coroutine (github.com)
Ellpeck/Coroutine: A simple implementation of Unity's Coroutines to be used for any C# project (github.com)
utamaru/unity3d-extra-yield-instructions:Unity3D 协程的其他自定义 yield 指令 (github.com) 
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用多少眼泪才能让你相信

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表