UnityCoroutineEX
来源:互联网 发布:软件测试是什么意思 编辑:程序博客网 时间:2024/04/30 06:23
新的风暴已经出现~
由于在最初使用unity时,对协程不了解,滥用出现了很多坑,导致内心一直是拒绝的,之前比较倾向于使用回调的方式。不过近来感觉unity实现的协程还是很好的,可以把分散在帧中的行为直观的表达出来,只要能了解它的一些规律加以应用,逻辑会简单很多。
有别于之前那篇探索性的文章,这里主要是应用上的增强,解决一些原生接口的缺陷,比之之前有更多优点:内部采用的unity的原生协程接口启动协程和yield,因此不需要对yield的返回值做解析,unity支持的yield类型这里都会支持;采用栈保存迭代器,天生实现了嵌套信息的保存。
Unity协程最大的问题我认为是在于,协程被驱动时没有一个嵌套关系,简单的说,一个协程中yield另一个协程时,调用接口中止外层的协程,内部的协程不会被停止。此外,在静态函数里没办法书写一个嵌套的协程,因为StartCoroutine是实例方法,所以静态函数里不能yield其它协程。
因此有下文中的扩展,但要注意的是,不能和unity的原生接口混用。
它把嵌套的的协程分解为多个线性排列的迭代器,并用栈来保留了嵌套关系,只需停止最外层的协程,所有内嵌的协程也会中止执行。并且,它是一个MonoBehaviour单例,协程都是委托它执行的,它开放出来的方法都是静态的,因此使用时,不需要限制调用者继承MonoBehaviour以及必须是实例方法。当然,也就意味着调用者被摧毁时,协程不会自动停止,需要手动停止,这算是稍弱于原生方法的地方。
using System.Collections;using System.Collections.Generic;using UnityEngine;/// <summary>/// unity3d原生协程扩展,不能与MonoBehaviour的StartCoroutine混用/// </summary>public class UnityCoroutineEX : Singleton<UnityCoroutineEX> { /// <summary> /// 协程handler /// </summary> public class CoroutineEX:IEnumerator { public Coroutine coroutine; public IEnumerator function; Stack<IEnumerator> stack2 = new Stack<IEnumerator>(); public override string ToString() { return "CoroutineEX:"+function; } public CoroutineEX(IEnumerator function) { this.function = function; Reset(); } public void Clear() { stack2.Clear(); } public object Current { get { if (stack2.Count<=0) { return null; } var top = stack2.Peek(); if (top!=null) { return top.Current; } return null; } } public bool MoveNext() { IEnumerator top=null; do{ if (stack2.Count <= 0) { return false; } top = stack2.Peek(); if (top.MoveNext()) { var obj = top.Current; if (obj is CoroutineEX) { var ex = obj as CoroutineEX; stack2.Push(ex.function); top = stack2.Peek(); } else { return true; } } else { stack2.Pop(); } } while (top != null); return false; } public void Reset() { stack2.Clear(); //function.Reset(); stack2.Push(function); } } /// <summary> /// 运行协程,不能yield返回值 /// </summary> /// <param name="function"></param> /// <returns></returns> public static CoroutineEX StartCoroutineEX(IEnumerator function) { var handler = new CoroutineEX(function); handler.coroutine = Instance.LoopDirver(handler); return handler; } /// <summary> /// 在协程内yield协程时用此方法 /// </summary> /// <param name="function"></param> /// <returns></returns> public static CoroutineEX InnerCoroutine(IEnumerator function) { return new CoroutineEX(function); } /// <summary> /// 中止协程 /// </summary> /// <param name="handler"></param> public static void StopCoroutineEX(CoroutineEX handler) { if (handler.coroutine!=null) { Instance.StopCoroutine(handler.coroutine); } else { handler.Clear(); } } Coroutine LoopDirver(CoroutineEX coroutine) { return StartCoroutine(_LoopDirver(coroutine)); } IEnumerator _LoopDirver(CoroutineEX coroutine) { if (!coroutine.MoveNext()) { yield break; } while (true) { var curr = coroutine.Current; yield return curr; if (!coroutine.MoveNext()) { break; } } }}
阅读全文
0 0