首页 > 代码库 > Unity3D之协程

Unity3D之协程

  Unity3D提供了一个工具叫做“协程”,所谓协程就是使用StartCoroutine()里面添加一个方法来调用该方法。对这个被调用的方法有如下规定:返回值必须是IEnumerator类型。那么为什么要使用协程呢?通常这是为了应付某一类需要,比如想要延时执行某一段代码,或者使用www进行一些请求和加载等阻塞操作。

  协程与多线程没有关系。协程每一帧都执行,时间段位于LateUpdate之后。所以说它只不过是在主线程里面每帧执行的一个函数而已。协程使用的原理类似于foreach循环,都是使用迭代器来实现,因此它也包括IEnumerator接口的Current属性和MoveNext()方法。这两个东东都是迭代器比较重要的内容。

  MSDN上对Current的解释为:Gets the current element in the collection,对MoveNext()的解释为:Advances the enumerator to the next element fo collection。从这两个解释可以看出来,Current返回的是集合当前的元素,MoveNext()推动循环向下一个元素。MoveNext()的返回值是bool,当返回true时,就向下走一级,返回false,则停止。假如循环到最后一个元素,肯定返回false。

  对于协程来说,当进行至yield return语句时,检查yield return后面的条件是否满足,如果满足,则执行后面的代码。如果不满足,则记录下该位置,下一帧继续检查,直到满足为止。这里体现了协程的主要作用了,假如你用www下载一个数据,你肯定想知道什么时候下载完。只有下载完了yield return www的下一行才会得到执行。

  下边看一个测试类,此类来自网络,通过一个协程内的循环来交替执行另外两个协程。注意,这些协程都是在主线程里面,可以随意访问Unity3D的对象和组件。

using System;using System.Collections.Generic;using System.Linq;using UnityEngine;using System.Collections;[RequireComponent(typeof(GUIText))]public class Hijack : MonoBehaviour {        //This will hold the counting up coroutine    IEnumerator _countUp;    //This will hold the counting down coroutine    IEnumerator _countDown;    //This is the coroutine we are currently    //hijacking    IEnumerator _current;        //A value that will be updated by the coroutine    //that is currently running    int value = http://www.mamicode.com/0;        void Start()    {        //Create our count up coroutine        _countUp = CountUp();        //Create our count down coroutine        _countDown = CountDown();        //Start our own coroutine for the hijack        StartCoroutine(DoHijack());    }        void Update()    {        //Show the current value on the screen        guiText.text = value.ToString();    }        void OnGUI()    {        //Switch between the different functions        if(GUILayout.Button("Switch functions"))        {            if(_current == _countUp)                _current = _countDown;            else                _current = _countUp;        }    }        IEnumerator DoHijack()    {        while(true)        {            //Check if we have a current coroutine and MoveNext on it if we do            if(_current != null && _current.MoveNext())            {                //Return whatever the coroutine yielded, so we will yield the                //same thing                yield return _current.Current;                if(_current.Current!=null)                Debug.Log(_current.Current.ToString());//wait for seconds OR null            }            else                //Otherwise wait for the next frame                yield return null;        }    }        IEnumerator CountUp()    {        //We have a local increment so the routines        //get independently faster depending on how        //long they have been active        float increment = 0;        while(true)        {            //Exit if the Q button is pressed            if(Input.GetKey(KeyCode.Q))                break;            increment+=Time.deltaTime;            value += Mathf.RoundToInt(increment);            yield return null;        }    }        IEnumerator CountDown()    {        float increment = 0f;        while(true)        {            if(Input.GetKey(KeyCode.Q))                break;            increment+=Time.deltaTime;            value -= Mathf.RoundToInt(increment);            //This coroutine returns a yield instruction            yield return new WaitForSeconds(0.1f);        }    }}

  现在简单解释下该类。首先定义了三个IEnumerator接口类型的变量用来接受协程的返回值,在Start方法里面调用其中一个DoHijack()协程。这个协程里面有一个无限循环,在该循环里面检查_current是否赋值了,如果有值就调用该IEnumerator接口里面的MoveNext()方法,相当于每次循环都执行一遍_current对应的方法。至于_current.Current则返回了两个协程CountUp和CountDown的返回值,输出一下得到值为Null或WaitForSeconds(),恰恰是yield return后跟的返回值。

Unity3D之协程