zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    ubuntu重复登录问题
    CUDA相关问题
    pytorch安装(使用pip3装到conda环境下)
    ubuntu16.04 anaconda的安装和卸载
    vscode插件安装失败的解决方案
    使用ffmpeg进行视频截图
    Spring加载早期获取BasePackage
    chrome最耐看的主题
    针对MySQL的MVCC多版本并发控制的一些总结
    docker创建mysql容器,并挂载数据+配置
  • 原文地址:https://www.cnblogs.com/timeObjserver/p/5985924.html
Copyright © 2011-2022 走看看