8. Unity3D中的协程Coroutine

主要介绍Unity中如何使用协程,协程是如何通过迭代器实现的,迭代器中的状态转换

一、Unity中如何使用协程

因为Unity中在更新数据时,一定会在一帧内将相关函数运行完,再一次性展示出来,如果你希望在游戏中显示数据改变的过程,那么就需要用到协程。一个比较典型的例子是加载界面时的进度条,如果不用协程,那么上一帧进度条显示0%,然后开始加载场景,下一帧进度直接跳到100%,不会显示中间的数据变化。

协程的功能是中断函数运行,返回一个值,让Unity先运行其他函数,显示该帧画面,然后继续从上次返回的地方继续运行下去。一般将需要及时反馈到画面上的数据变化的函数写在一个协程函数中,如进度条的进度情况:

     private IEnumerator StartLoading()
     { 
        while (displayProgress < toProgress)
        {
            ++displayProgress;
            slider.value = displayProgress;
            text.text = "Loading: " + displayProgress + "%";
            yield return new WaitForEndOfFrame();
        }
     }

1. 可以看到协程方法返回值为IEnumerator类型,其实还可以是IEnumerable类型的。两者的区别稍后会讲。

2. 返回的语句会在return前加关键字yield,返回的值通过new WaitForEndOfFrame()生成一个WaitForEndOfFrame类的对象,再将该对象向上转型成IEnumerator接口的对象(注意,C#中接口可以指向一个子类的对象实例)。一般的返回值都是通过某个类的构造方法生成的IEnumerator类的对象(其实是生成该子类的对象,但是由子赋给父,不需要强制类型转换),比较常见的构造方法有:null,WaitForSeconds(float second)(这个函数会及时返回,但是过second秒后才会执行接下来的代码),WaitForFixedUpdate()。从他们的名字就能知道他们的功能。

8. Unity3D中的协程Coroutine_第1张图片

 

3. 通过StartCoroutine方法开启协程,这个方法是MonoBehaviour的静态函数,它有两种重载版本:

Coroutine StartCoroutine(IEnumerator routine);如:StartCoroutine(methodName(a,b))

Coroutine StartCoroutine(string methodName,object value=null);如:StartCoroutine(“methodName”,a)

4. 可以通过StopCoroutine 来停止一个协程,如协程函数是一个死循环,那么就会一直运行下去,这时候在中间设置一个时间,一定时间后调用StopCoroutine 就会结束循环。

很多人刚开始使用协成时,会觉得协成是一个线程,但其实不是的,协程只是让程序在一定地方中断,然后等待时机成熟再继续执行剩下的代码。

二、协程是如何通过迭代器实现的

其实在协程函数中就可以看到IEnumerator(翻译为:计数者)等C#中的迭代器接口

1. 什么是迭代器,迭代器可以在一个容器中遍历元素,追踪当前元素,识别下一个元素,当我们在使用Foreach遍历数据时,其实内部的原理就是使用迭代器完成的。

2. 任何迭代器都需要实现IEnumerable或者IEnumerator或者他们的泛型形式。

3. 协程就是将一个函数分成很多段,每一段可以看做一个元素,返回的IEnumerable对象在StartCoroutine函数中通过迭代器的形式运行当前元素,下一次运行时就找到下一个元素(运行下一段代码)。

下面介绍一下IEnumerable与IEnumerator是如何实现迭代器的。

迭代器一个current属性,指向当前元素,一个MoveNext()方法,获得下一个元素,而IEnumerable没有这两个东西,它通过函数获得一个IEnumerator,在IEnumerator中有这两个东西,为什么不直接在IEnumerable中实现呢,因为当有两个不同的迭代器对数据进行迭代(如嵌套的foreach),我们希望两者互不影响,所以由IEnumerator负责处理。

在第一次调用MoveNext方法之前,不会运行任何代码,第一次调用MoveNext方法,在遇到yield return语句时停止,这时会获得第一个元素(也就是运行第一段代码)。

 

三、迭代器(iterator)中的状态转换。

我们已经知道协程是通过迭代器实现的,那么迭代器的内部实现原理是什么呢,答案是状态机。迭代器有四个可能的状态,Before、running、Suspended(暂停的)、After。

这里需要注意一点:与一般的函数调用不同,一般的函数调用,在运行a()时就会马上执行a方法中的代码,但是在调用一个使用了迭代器块的函数时,方法不会立刻执行,

1. 而是通过该函数的返回值实例化一个IEnumerable的对象,

2. 再由该对象的GetEnumerator()获得一个IEnumerator对象,

3. 当调用IEnumerator对象的MoveNext()函数时,我们写的函数代码才会被执行。

这些应该就是StartCoroutine函数所做的事。

那么迭代器的状态转换就主要关注获得的IEnumerable与IEnumerator。

在执行了1后,状态为-2,只有IEnumerable有,因为此时还没有IEnumerator,

执行了2后,状态为0,表示Before状态,且MoveNext方法还没有被调用过。

-1状态表示Running或者After状态

整数1、2、3……用来标识第几个元素,即代码是要从哪里继续。

 

此外,本书还讲解了一个很常见的使用协程的例子,即协程与Unity3D中的WWW类一起使用来加载页面。

 

 

 

 

 

 

 

 

 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

 

 

你可能感兴趣的:(Unity)