首先我们举个简单的例子,实现延迟销毁的功能(Destroy方法的一个重载版本实现了这个功能,我们这里只是为了方便示例):
using UnityEngine;
using System.Collections;
public class DelayedDestroyTest : MonoBehaviour {
public float delayedSeconds = 5f;
private IEnumerator coroutineEnumerator;
// Use this for initialization
void Start () {
coroutineEnumerator = DelayedDestroy ();
StartCoroutine (coroutineEnumerator);
}
IEnumerator DelayedDestroy()
{
Debug.Log (string.Format("Game Object will be destroyed after {0} seconds", delayedSeconds));
yield return new WaitForSeconds (delayedSeconds);
Destroy (this.gameObject);
}
}
执行DelayedDestroy方法,返回了一个IEnumerator(至于为什么要使用一个私有变量,后面会介绍到),然后以这个返回值为参数调用StartCoroutine方法,就开启了一个协程。
重点在DelayedDestroy方法里:
第一行打印了一行log,这一行没有也没关系。
第二行yield return了一个WaitForSeconds类型的实例,这就告诉了Unity,在5秒(delayedSeconds)之后,再回来执行后面的代码。
第三行执行的Destroy方法(5秒之后)。
将它挂载到Unity的一个对象上面,点击运行,默数5秒,就会发现这个对象被销毁了。
我们再举一个例子,一个渐隐(Fade)的功能:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Renderer))]
public class CoroutineFadeTest : MonoBehaviour {
// Use this for initialization
void Start () {
Material mat = GetComponent ().material;
StartCoroutine ("Fade", mat);
}
IEnumerator Fade(Material mat)
{
Color col = mat.color;
while (col.a > 0f)
{
col.a -= 0.01f;
mat.color = col;
yield return null;
}
}
}
点击运行,你会发现这个Cube会慢慢变透明,直到看不见。道理跟上面的相似,只不过我们使用了StartCoroutine的重载方法,参数为string类型的方法名(并且可以穿参数——mat)。
如果我们要停止协程怎么办?这就需要使用StopCoroutine方法了,在CoroutineFadeTest的类里面添加Update方法:
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.S)) {
StopCoroutine ("Fade");
}
}
运行的时候按下S键,渐隐就会停止了。那么延迟销毁的功能里该怎么写呢?貌似使用跟上面相同的方法不行呢?
网上说,StopCoroutine只能终止使用了StartCoroutine的string参数的重载版本开启的线程(有本书上也是这么说的)(⊙o⊙)…好吧,这就厉害了。
不过本文前面挖了个坑,正好现在用到了。
void Update () {
if (Input.GetKey (KeyCode.S)) {
Debug.Log ("stop");
StopCoroutine (coroutineEnumerator);
}
}
注意:StartCoroutine和StopCoroutine的参数类型要对应。
其实还有一种办法,使用yield break。在类里面添加一个bool值breakCoroutine,Update方法里面,当按下S的时候,设置breakCoroutine为true。然后修改DelayedDestroy方法:
IEnumerator DelayedDestroy()
{
Debug.Log (string.Format("Game Object will be destroyed after {0} seconds", delayedSeconds));
yield return new WaitForSeconds (delayedSeconds);
if (breakCoroutine) {
yield break;
}
Destroy (this.gameObject);
}
最后补上yield return后面可以跟的对象类型:
null:会在下一帧所有的Update方法执行之后再执行后面的代码。
WaitForEndOfFrame:会在本帧结束时且这一帧显示在屏幕上之前……
WaitForSeconds:等待sec(输入参数)秒之后……
WaitForFixedUpdate:会在下一次所有的FixedUpdate方法执行完之后……
WWW:在WWW下载完成之后……
StartCoroutine:等另一个协程执行过一次之后……
WaitUntil:当输入的参数(委托)为true的时候……
WaitWhile:当输入的参数(委托)为false的时候……
(关于委托,参考C#语法小知识(四)委托delegate和C#语法小知识(十二)匿名方法与Lambda表达式)
注:yield return返回的值跟协程方法(DelayedDestroy和Fade)的返回值并不相同。(参考C#语法小知识(十四)迭代器(IEnumerable/IEnumerator/yield))