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;            }        }    }}


原创粉丝点击