在http://unitygems.com/advanced-coroutines/ 里展示了一个在两个Coroutine间切换的Demo。
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());
// _current = _countUp;
}
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()
{
Debug.Log("Test()");
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; //should write like this, or yield return new WaitForSeconds(0.5f) in CountDown() has no effect.
}
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.5f);
}
}
}
需要注意到,上述代码中,
IEnumerator DoHijack()
{
Debug.Log("Test()");
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; //should write like this, or yield return new WaitForSeconds(0.5f) in CountDown() has no effect.
}
else
//Otherwise wait for the next frame
yield return null;
}
}
{
Debug.Log("Test()");
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; //should write like this, or yield return new WaitForSeconds(0.5f) in CountDown() has no effect.
}
else
//Otherwise wait for the next frame
yield return null;
}
}
中间的yield return _current.Current;这一行要是换为了yield return null;或者yield return 2等任意不需要耗时计算的东东,CountDown()里的WiatForSeconds就会没有效果。 这是因为DoHijack和CountDown()是两个不同的Coroutine,虽然是在DoHijack()里调用的CountDown(),但两者相互独立,DoHijack不用等待CountDown(),除非在代码里被要求这么干。
CoroutineA遇到yield就马上返回了,Unity就可以去执行其他的Coroutine,只是在再次进入CoroutineA时,需要检测上次那个yield语句的内容是否已经满足。其他Coroutine等待CoroutineA.Current时也需要等待CoroutineA的那个yield语句的内容是否已经满足。
于是在http://blog.csdn.net/u010153703/article/details/38557237 里,我们的Fibonacci数列若想看到数字缓慢地出现,可以修改如下:
using UnityEngine;
using System.Collections;
using System;
public class Fibonacci : MonoBehaviour {
//int Fk = 0;
IEnumerator Fib()
{
int Fkm2 = 1;
int Fkm1 = 1;
yield return 1;
yield return 1;
while (Fkm2 + Fkm1 < int.MaxValue)
{
int Fk = Fkm2 + Fkm1;
Fkm2 = Fkm1;
Fkm1 = Fk;
yield return new WaitForSeconds(0.5f);
yield return Fk;
}
}
IEnumerator ShowFib()
{
IEnumerator fib = Fib ();
// StartCoroutine(fib); //should not be written here if you want to use MoveNext() which meaning RunCoroutine yourself
for (int i=0; i<20; ++i)
{
if (!fib.MoveNext())
break;
Debug.Log(fib.Current);
yield return fib.Current;
}
yield return null;
}
// Use this for initialization
void Start () {
StartCoroutine(ShowFib());
//ShowFib();
}
}