Unity中协程的主动调用

发表于2017-05-27
评论0 1.6k浏览
在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>

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引