协程(IEnumerator)的使用

来源:互联网 发布:淘宝军用防毒面具价格 编辑:程序博客网 时间:2024/05/19 13:57

               在Unity中,并没有多线程的概念(体现在当使用多线程的时候,线程里面不可以出现任何unity的类或者结构体),但是unity本身封装了一个类似于多线程的开启另一段逻辑的方法:协同程序。协程跟线程很类似,都是另开一段逻辑,又跟主线程相互联系。但是不同之处也有很多,比如协程是程序员可控的,而线程是由CPU决定的;线程的关闭需要手动关闭,协程在程序结束以后,由unity垃圾回收机制清理。最大的体现就是协程是属于unity的,可以在unity随意使用。

    协程是封装于Monobehaviour,但是却不由Monobehaviour控制,由GameObject控制处理。协程的调用是在LateUpdate后调用,遇到yield挂起,如果满足条件,将会执行yield下面的代码。可以在unityAPI中查看到这个执行顺序:

      因此,协程有极大的优势:随开随关。那么利用协程就可以做到很多事情,一般是关于变化过程的功能,像计时器,特效等。

              
那么接下来谈谈协程是如何使用的,以及用协程可以做的功能。
1、协程的开启:

    1)通过名称开启

 private void Start()    {        StartCoroutine("test");//这里名字要和协程的方法名一致    }    IEnumerator test()    {        yield return null;    }


   (2)通过方法开启


 private void Start()    {        StartCoroutine(test());    }    IEnumerator test()    {        yield return null;    }

     使用名称开启的时候,一定要注意:这个协程没有参数,如果有参数,是不可以通过名称开启的,只能通过方法来开启。



2、协程的停止:
   


       协程停止类似于开始协程,使用关键字StopCoroutine()。里面有两个参数,需要注意的是,如果你开启协程使用的是通过名称,那么停止也必须使用名称;反之,如果通过方法开启,也必须通过方法来停止。所以里面的参数不要填错就行。另外有一种方法是: StopAllCoroutines()。这个方法是立马停止类里面的所有协程。这两种方法是比较简单,只需要调用就行了。但是接下来介绍三种另外停止的方法:



  (1)通过协程的返回值停止:

  Coroutine coroutine;    private void Start()    {        coroutine =  StartCoroutine("test");    }       IEnumerator test()    {       yield return null;    }



       开启协程的返回值是Coroutine,通过StopCoroutine(coroutine)也可以停止协程。原理就是类似于引用类型,将地址赋予一个变量。这是因为开启协程和变量在堆中指向的是同一个地址。


(2) 通过满足yield结束


       协程是一种迭代器,遇到yield挂起,也就是等待的意思。那么方法执行结束后,协程就结束了。。但是在循环的时候,由于协程里的变量是与主线程相互联系的,那么与外部联系同样也可以结束协程。那么举个例子:


 float checkTime = 0;    private void Start()    {       StartCoroutine("test");    }    private void Update()    {        if(Input.GetMouseButtonDown(0))        {            checkTime = 101;        }    }    IEnumerator test()    {        while(true)        {            if(checkTime <= 100)            {                checkTime += Time.deltaTime;                yield return null;            }            else            {                yield break;            }        }    }




      yield break 跳出循环。如果不是放在循环里,那么就类似于方法中的return。




      这个时候,如果我们按下鼠标左键,协程就不满足条件,那么跳出循环就结束了。所以通过这里可以看出,协程的字段与主线程,外部都有联系,通过外部修改,协程内部同样也能得到。


(3) 通过GameObject控制:



      协程是封装于Monobehaviour中,但是不由Monobehaviour控制,体现在:



 private void Start()    {       StartCoroutine("test");       enabled = false;    }     IEnumerator test()    {      yield return null;    }




通过控制脚本,将enable设置为false,如果是在循环体中,这时候会发现协程并没有停止,依然在运行。



那么这个时候如果想控制不让协程运行,可以这么写


    gameObject.SetActive(false);
     

        由于协程是受gameobject控制,将gameobject设置为false,那么协程就会随即停止,这个时候再启用物体,协程是不会继续得。所以设置为false,协程是停止不是暂停。
不过不推荐这样使用,除非是要将物体禁用了。




使用协程需要注意:

(1)传递参数得时候是不能使用ref,out传递参数

(2)协程一定要有yield

(3)如果通过名称开启协程,这个协程一定是没有参数得。

(4)使用StopCoroutine停止协程得时候,要跟开启协程得时候保持一致,通过什么类型开启就通过什么类型关闭。





3、协程的运行时间

    协程是在lateUpdate后处理,处理速度与方法的速度一致。 举个例子:
 private void Start()    {       StartCoroutine("test");       print("Start");    }        IEnumerator test()    {        print("test");        yield return null;    }


这个时候在Start开始调用,那么打印就是先打印test,再打印Start。意思是都在这一帧调用,假如我们等待一帧:

private void Start()    {       StartCoroutine("test");       print("Start");    }        IEnumerator test()    {        print("test");        yield return null;        print("yield return null");    }


那么打印顺序就变成了先test,后Start,后yield return null。所以协程的处理速度也是方法的处理速度,在同一帧中,自上而下调用。相当于两条路的车速度一模一样。




4、yield 参数的大致了解:


     yield是控制协程暂停,结束的迭代,在yield后有很多参数可以做到等待,就不做演示,就将参数解释一下:
    


   
    yield return null; // 下一帧再执行后续代码    yield return 0; //这里不管填多少,都是等待一帧。如果要等待多少秒,用WaitForSeconds或者WaitForSecondsRealtime    yield break; //跳出循环或者结束协程    yield return AsyncOperation;//等待异步操作    yield return WWW;//等待WWW加载完成    yield return new WaitForEndOfFrame();//等待所有的摄像机和GUI等被渲染完成    yield return new WaitForSeconds(1.5f);//等待1.5秒,这里单位是秒(注意:这里的时间是默认乘以Time.timeScale);    yield return new WaitForSecondsRealtime(1.5f);//等待1.5秒,这里单位是秒(注意:这里的时间不乘Time.timeScale);    yield return WaitForFixedUpdate();//等待下一帧FixedUpdate开始


如果想一起探讨技术,可以添加扣扣群:478462732。


不过首先声明:我是菜鸟。







原创粉丝点击