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 = 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)