Unity 协程Coroutine综合测试
转载
1 using UnityEngine;
2 using System.Collections;
3 using System.Text;
4
5 public class rotCube : MonoBehaviour {
6
7 //示例,如何为一个自定义对象实现GetEnumerator接口,从而可以对该对象使用foreach
8 //这种写法是c#2.0才有的,通过yield关键字与IEnumerator返回类型组合成一个枚举器
9 //C#会自动生成一个IEnumerator类,该类实现了MoveNext(),Reset(),Current
10 //在C#2.0之前,我们必须自己来写一个IEnumerator类,才实现上面的接口与属性
11 class MyCalc : IEnumerable{
12 int rest = 1;
13 public int x = 1;
14 public int y = 1;
15
16 public IEnumerator GetEnumerator ()
17 {
18 for(int i=0; i<y; ++i)
19 {
20 yield return rest = x * rest;
21 }
22 }
23 }
24
25 //示例,如何将一个函数写成可以被枚举的对象(拥有MoveNext(),Reset(),Current)
26 //C#会自动生成一个IEnumerator类,该类实现了MoveNext(),Reset(),Current
27 //在C#2.0之前,我们必须自己来写一个IEnumerator类,才实现上面的接口与属性
28 IEnumerable calc(int x, int y){
29 int rest = 1;
30 for(int i=0; i<y; ++i)
31 {
32 yield return rest = x * rest;
33 }
34 }
35
36 IEnumerator waitprint(){//协程返回类型必须为IEnumerator,它不认IEnumerable,如yield return DoCheck (),若DoCheck为IEnumerable,则DoCheck不会被执行
37
38 //StartCoroutine("DoCheck");//启动一个新的协程
39 //yield return DoCheck (); //在这里进入死循环,若改为StartCoroutine("DoCheck");则不会进入死循环,只会另外启动一个协程
40
41 yield return new WaitForSeconds (5); //暂停5秒,若流程走到了这里,协程将在这里阻塞5秒才执行下面的代码
42 yield return new GameObject ();
43 yield return 2;
44 }
45 IEnumerable waitPrint(){
46 yield return 1;
47 yield return 2;
48 }
49
50 IEnumerator DoCheck(){
51 for(;;){
52 Debug.Log ("doecheck");
53 //协程调用频率最高是每帧一次,这里我们指定的等待时间小于一帧,并不能达到一帧调用多次docheck的效果
54 yield return new WaitForSeconds (0.0001f); //0.1毫秒,1/0.0001F = 10000 fps,显然U3D不可能达到这个帧率
55 }
56 }
57
58 void Start () {
59
60 /************************************************************************/
61 /* 自定义对象的枚举测试,自定义方法的枚举测试,这是理解协程的基础 */
62 /************************************************************************/
63 StringBuilder sbd = new StringBuilder(50);
64 foreach(var n in calc (2, 8)){
65 sbd.Append (n);
66 sbd.Append (",");
67 }
68
69 sbd.Length = 0;
70 MyCalc omc = new MyCalc (){ x = 2, y = 8 };
71 foreach(var n in omc){
72 sbd.Append (n);
73 sbd.Append ((","));
74 }
75
76
77 /************************************************************************/
78 /* 协程综合测试 */
79 /************************************************************************/
80 //U3D协程特征:本质是一个返回值为IEnumerator的函数,函数中至少有一条yield return语句。
81 //协程必须由StartCoroutine来启动
82 //协程并非线程,线程是操作系统层的东西,协程是引擎层面由逻辑调用来实现的,是由一个线程操作出来的,在LUA中是由LUA状态机实现,在U3D是由U3D引擎状态机实现。
83 //在U3D中,协程是U3D引擎在每帧的update之后调用一次协程函数来实现,在update()中写一个死循环,会发现程序卡死,协程也不会执行了。这证明了协程和主线程是同一线程。
84 //UNITY手册的Execution Order of Event Functions一节详细讲解了协程的调用时机,从中可以看出协程只是主线程中的逻辑调用,并非一个新线程。
85
86 //StartCoroutine ("DoCheck");
87 //yield return waitprint (); //waitprint被完整执行
88 //yield return waitPrint (); //waitPrint没有被执行,U3D不认这种形式
89
90
91 //协程返回类型必须为IEnumerable。
92 //但不管一个函数的返回类型是IEnumerable还是IEnumerator,只要函数体中有一句yield return,编译器就会自动为该函数生成一个IEnumerator类型的对象。
93 //就可以使用此迭代器对象的MoveNext(), Current等方法,属性。若是返回类型为IEnumerable,编译器还会生成GetEnumerator()方法。
94 waitprint ();//直接调用协程函数无效,不会进入该函数执行,这时仅相当于返回了一个IEnumerator迭代子的临时对象,并没有执行具体代码。
95
96 //只有如下调用,才会完整的执行协程函数
97 IEnumerator i = waitprint ();
98 i.MoveNext (); //从函数入口执行到yield return new WaitForSeconds (5);
99 i.MoveNext (); //从上一个yield语句末执行到yield return new GameObject ();
100 i.MoveNext (); //从上一个yield语句末yield return 2;
101 //下面这种写法并不能达到上面的效果,原因是每次waitprint ()返回的是一个不同的临时对象,通过gethashcode可以发现。
102 //waitprint ().MoveNext ();
103 //waitprint ().MoveNext ();
104 //waitprint ().MoveNext ();
105
106 //返回值为IEnumerable类型的示例
107 //只有返回值为IEnumerable的方法才能用于foreach,因为它要求实现GetEnumerator
108 i = waitPrint ().GetEnumerator ();
109 i.MoveNext ();
110 i.MoveNext ();
111 i.MoveNext ();
112
113 print ("done");
114 }
115
116 void Update(){
117 transform.Rotate (0, 2, 0);
118 }
119 }
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。