序
刚学习Unity的时候,总会不时看到文章说合理使用协程(Coroutine)能更好实现一些功能。今天不说怎么使用协程,相信网上已经有非常多的资料了,重点分析的目标是当初从未上心的一个函数StopAllCoroutines。
1.函数意义
第一眼看到函数名的时候,很有迷惑性。Stop All?!乖乖,这个函数有点霸道啊,直接就停掉所有的协程,这岂不是会停掉一些我不想停掉的协程呢?算了,这种接口还是少用为妙。不过后来仔细想想,Unity这么成熟一个商业引擎,做设计的工程师不至于这么无聊弄一些意义不大的接口吧。仔细看了看官方接口描述:
这些能够解释清楚了,只是停掉当前behaviour上的所有协程,不会影响到其他物体。做个测试,创建一个C#文件,名字叫Coroutine1,代码如下:
using UnityEngine;
using System.Collections;
public class Coroutine1 : MonoBehaviour {
// Use this for initialization
void Start () {
StartCoroutine (Cor1 ());
StartCoroutine (Cor2 ());
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.Alpha1))
StopAllCoroutines();
}
IEnumerator Cor1(){
Debug.LogError ("Start Cor1");
int i = 0;
while (true) {
Debug.LogError ("Cor1 frame " + i);
i++;
yield return new WaitForSeconds(0.5f);
}
Debug.LogError ("end Cor1");
}
IEnumerator Cor2(){
Debug.LogError ("Start Cor2");
int i = 0;
while (true) {
Debug.LogError ("Cor2 frame " + i);
i++;
yield return new WaitForSeconds(0.5f);
}
Debug.LogError ("end Cor2");
}
}
讲脚本随意挂到一个GameObject上,运行程序,可以看到Cor1和Cor2函数中while里面的日志交替输出。按下键盘上数字1后,停止输出日志,说明StopAllCoroutines确实停止了当前脚本上的所有协程。至于它真的会不会停掉所有物体上的所有协程,我不想贴代码,大家自己写个脚本去验证吧。
2.What is this behaviour?
搞清楚了函数的大致应用情况,但是仍有一丝疑惑。
回到接口本身,按照接口描述,是停止this behaviour上所有的协程,这个behaviour指的到底是挂载了我们所写脚本的GameObject上的这一个Coroutine1的实例,还是指场景里面所有的Coroutine1 实例呢?再做一个测试,新建一个脚本Coroutine2,代码如下:
using UnityEngine;
using System.Collections;
public class Coroutine2 : MonoBehaviour {
// Use this for initialization
void Start () {
StartCoroutine (Cor ());
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.Alpha1) && name == "Cube1") {
StopAllCoroutines();
}
}
IEnumerator Cor(){
Debug.LogError ("Start Cor " + name);
while (true) {
Debug.LogError("Update Cor " + name);
yield return new WaitForSeconds(0.5f);
}
}
}
在场景中创建2个GameObject “Cube1” 和 “Cube2”,再为两个物体分别挂载Coroutine2脚本。为了方便,代码中直接使用了物体名字,而没有通过其他方式来加以区分。
运行游戏可以看到仍然是两条日志交替输出。当按下数字键1后,日志不再输出“Start cor 1”,说明Cube1上脚本里面启动的协程已经被停止了,而Cube2上的协程还在继续运行。
很显然,输出结果已经告诉了我们答案。StopAllCoroutines只会停止调用这个接口的脚本实例对象上的所有协程,而非调用这个接口脚本的所有实例对象。
结语
可能有人会说,这个接口描述一看就知道结果是这样啊,还需要这样写脚本来验证?!请原谅一个强迫症患者偶尔咬文嚼字想要对于疑惑进行验证的心情。与其懵懵懂懂前进,不如怀着喜悦心情去寻究真相,这个过程本来就是满怀乐趣呢。