Unity中协程的主动调用
发表于2017-05-27
在Unity中,协程的使用频率非常的高,在项目中,有的时候需要手动控制协程的更新,也就是重写StartCoroutine方法。下面就给大家介绍下协程的主动调用,具体如下:
调用方法:
另外,协程遍历的方法,其实是一个树的深度遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Reflection; public class CoroutineManager { public Clock clock { get ; private set ; } private HashSet cIters ; private List itAddTemp; private List itDelTemp; private CoroutineManager() { cIters = new HashSet(); itAddTemp = new List(); itDelTemp = new List(); clock = new Clock(); } private static CoroutineManager instance = null ; public static CoroutineManager Instance { get { if (instance == null ) { instance = new CoroutineManager(); } return instance; } } public static float time { get { return Instance.clock.time; } } public CoroutineIter StartCoroutine(IEnumerator _it) { var iter = new CoroutineIter(_it); itAddTemp.Add(iter); return iter; } public void StopCoroutine(CoroutineIter cIter) { if (cIter != null ) { itDelTemp.Add(cIter); } } public bool doUpdate( float dt) { if (itAddTemp.Count > 0) { // 添加 itAddTemp.ForEach(it => { cIters.Add(it); }); itAddTemp.Clear(); } if (clock.tick(dt) && cIters.Count > 0) { foreach (var i in cIters) { i.doUpdate(dt); } cIters.RemoveWhere(i => i.isEnd); } if (itDelTemp.Count > 0) { // 删除 itDelTemp.ForEach(it => { cIters.Remove(it); }); itDelTemp.Clear(); } return cIters.Count > 0; } public class Clock { public int frame { get ; private set ; } public float time { get ; private set ; } public float dt { get ; private set ; } public void reset() { time = dt = 0; } public bool tick( float _dt) { if (frame < Time.frameCount) { dt = _dt; time += _dt; frame = Time.frameCount; return true ; } return false ; } } } public class CoroutineIter { public bool isEnd { get ; private set ; } Stack stack = new Stack(); IEnumerator it; public CoroutineIter(IEnumerator _it) { it = _it; isEnd = it == null ; } public void doUpdate( float dt) { if (!isEnd) { if (it.MoveNext()) { dealCurrent(it.Current); } else { it = stack.Count > 0 ? stack.Pop() : null ; } isEnd = it == null ; } } private void dealCurrent( object cur) { if (it.Current is IEnumerator) { stack.Push(it); it = it.Current as IEnumerator; } else if (it.Current is WaitForSeconds) { stack.Push(it); it = new MyWaitForSecond(it.Current as WaitForSeconds); } } } class MyWaitForSecond : CustomYieldInstruction { private float duration; private float startTime; CoroutineManager cm; public MyWaitForSecond(WaitForSeconds wfs) { duration = GetPrivateFieldValue< float >(wfs, "m_Seconds" ); cm = CoroutineManager.Instance; startTime = cm.clock.time; } public override bool keepWaiting { get { return (cm.clock.time - startTime) < duration; } } private static T GetPrivateFieldValue( object obj, string propName) { if (obj == null ) throw new ArgumentNullException( "obj" ); Type t = obj.GetType(); FieldInfo fi = null ; while (fi == null && t != null ) { fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); t = t.BaseType; } if (fi == null ) throw new ArgumentOutOfRangeException( "propName" , string .Format( "Field {0} was not found in Type {1}" , propName, obj.GetType().FullName)); return (T)fi.GetValue(obj); } } float > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | using System; using System.Collections; using UnityEngine; public class Testtest : MonoBehaviour { CoroutineIter iter; void Start() { CoroutineManager.Instance.StartCoroutine(testx0()); //StartCoroutine(test0()); } void Update() { if (!CoroutineManager.Instance.doUpdate(Time.deltaTime)) { Debug.LogError( "=======EEEEEEEE=======" ); } } private IEnumerator testx0() { Debug.Log( "======={{{{ =======" ); yield return null ; var handler = CoroutineManager.Instance.StartCoroutine(testx1()); yield return new WaitForSeconds(3f); CoroutineManager.Instance.StopCoroutine(handler); Debug.Log( "======= }}}} =======" ); yield return new WaitForSeconds(1f); Debug.Log( "======= End =======" ); } private IEnumerator testx1() { int i = 0; while ( true ) { yield return new WaitForSeconds(0.3f); Debug.Log( ">>> " + (i++)); } } private IEnumerator test0() { yield return test1(); Debug.Log( "000000000000" ); yield return test2(); Debug.Log( "000000000000" ); } private IEnumerator test1() { Debug.Log( "111111 : " + Time.time); yield return new WaitForSeconds(1f); Debug.Log( "111111 : " + Time.time); } private IEnumerator test2() { Debug.Log( "222222 : " + Time.time); yield return new WaitForSeconds(2f); Debug.Log( "22222 : " + Time.time); } private IEnumerator testA() { for ( int i = 0; i < 3; i++) { yield return new WaitForSeconds(i); Debug.Log( "-1- " + CoroutineManager.time); } Debug.Log( "-2-" ); yield return null ; Debug.Log( "-3-" ); yield return new CC(); Debug.Log( "-4- " + CoroutineManager.time); yield return new WaitUntil( delegate { return CoroutineManager.time > 5; }); Debug.Log( "-5- " + CoroutineManager.time); yield return new WaitWhile( delegate { return CoroutineManager.time < 8; }); Debug.Log( "-6- " + CoroutineManager.time); } class CC : CustomYieldInstruction { int i = 0; public override bool keepWaiting { get { Debug.Log( "CC > " + i); return i++ < 10; } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | using UnityEngine; using UnityEditor; using NUnit.Framework; using System; using System.Collections; using System.Collections.Generic; public class NewEditorTest { [Test] public void EditorTest() { //Iterate (test01 (0)); Iterate(testA(), obj=>{ if (obj is YieldInstruction){ Debug.LogFormat( "!!YI: " + obj.GetType().Name); } else if (obj is CustomYieldInstruction) { Debug.LogFormat( "!!CYI: {0}, isIt? {1} " , obj.GetType().Name, obj is IEnumerator); } }); } private void Iterate(IEnumerator _it, System.Action< object > action = null ) { Stack stack = new Stack (); var it = _it; while (it != null ) { while (it.MoveNext ()) { if (action != null ) action (it.Current); if (it.Current is IEnumerator) { stack.Push (it); it = it.Current as IEnumerator; continue ; } } it = stack.Count > 0 ? stack.Pop() : null ; } } float time = 0; private IEnumerator testA() { for ( int i = 0; i < 3; i++) { Debug.Log ( "-1-" ); yield return new WaitForSeconds (i); } Debug.Log ( "-2-" ); yield return null ; Debug.Log ( "-3-" ); yield return new CC (); Debug.Log ( "-4-" ); yield return new WaitUntil ( delegate { time += 0.3f; Debug.Log( ">Time: " + time); return time > 10; }); Debug.Log ( "-5-" ); yield return new WaitWhile ( delegate { time += 0.3f; Debug.Log( ">Time: " + time); return time < 15; }); } class CC : CustomYieldInstruction { int i = 0; public override bool keepWaiting { get { Debug.Log ( "CC > " + i); return i++ < 10; } } } private IEnumerator test01( int l) { Debug.Log ( "----test01-{{{" ); print (1, l); yield return test02 (l+1); print (2, l); yield return null ; print (3, l); yield return test03(l+1); print (4, l); Debug.Log ( "}}}test01-----" ); } private IEnumerator test02( int l) { Debug.Log ( "----test02-{{{" ); print (1, l); yield return test03 (l+1); print (2, l); yield return null ; print (3, l); yield return test03(l+1); print (4, l); Debug.Log ( "}}}test02-----" ); } private IEnumerator test03( int l) { Debug.Log ( "----test03-{{{" ); print (1, l); yield return null ; Debug.Log ( "}}}test03-----" ); } private void print( int num, int level) { string rt = "" ; for ( int i = 0; i < level; i++) { rt += " " ; } Debug.LogFormat ( "{0}{1}" , rt, num); } } object > |