Unity 协程开启、停止与生命周期
StopAllCoroutines只会停止调用这个接口的脚本实例对象上的所有协程,而非调用这个接口脚本的所有实例对象。
协程被打断
使用Unity的MonoBehavior组件开启一段协同程序非常方便,但是应该注意如果这段程序需要运行一段较长时间,在运行期间,如果开启这段协同程序的组件被删除或SetActive(false) 隐藏了,则协程会被打断,这段程序就不在执行了,因此使用StartCoroutine要注意源组件的生命周期和协程的生命周期。
这种情况(或者有些类不继承自MonoBehaviour),若想要在这些类中使用StartCoroutine,则可以
//空 Mono 类
public class MonoStub : MonoBehaviour
{
}
newGameObject().AddComponent<MonoStub>().StartCoroutine("Test1");
不这样的话,在Unity5.6中会报错。
上面是Unity5.6.3P4上测试过,之前在Unity5.2.5上可以使用:
new GameObject().AddComponent().StartCoroutine("Test1");
例:一个协程在 yield return后运行过程中会因为父节点的暂时隐藏而打断协程,就可以单独挂一个独立的空组件来保证协程运行过程不会被中断
// 创建一个继承 MonoBehaviour 的空类
private class MonoStub:MonoBehaviour
{
}
private GameObject monoStub;
private IEnumerator routineLoadItems;
// 注意GC
private void OnDestroy()
{
StopCoroutine(routineLoadItems);
Destroy(monoStub);
}
public void SetData(List value)
{
this.transform.RemoveChildren();
if (this.gameObject.activeSelf)
{
//StartCoroutine(LoadItemList(value));
monoStub = new GameObject();
routineLoadItems = LoadItemList(value);
monoStub.AddComponent<MonoStub>().StartCoroutine(routineLoadItems);
}
}
//程序在下一帧中从当前位置继续执行
yield return 0;
//程序在下一帧中从当前位置继续执行
yield return null;
//程序等待N秒后从当前位置继续执行
yield return new WaitForSeconds(N);
//在所有的渲染以及GUI程序执行完成后从当前位置继续执行
yield new WaitForEndOfFrame();
//所有脚本中的FixedUpdate()函数都被执行后从当前位置继续执行
yield new WaitForFixedUpdate();
//等待一个网络请求完成后从当前位置继续执行
yield return WWW;
//等待一个xxx的协程执行完成后从当前位置继续执行
yield return StartCoroutine(xxx);
//如果使用yield break语句,将会导致协程的执行条件不被满足,不会从当前的位置继续执行程序,而是直接从当前位置跳出函数体,回到函数的根部
yield break;
协程开启与停止的对应方法:
注意点:
1、StopCoroutine(方法名字符串or方法名引用);
注意:如果启动(StartCoroutine)用的是方法名引用,结束(StopCoroutine)也必须用方法名引用,否则结束不了。
2、StopAllCoroutine(),只能结束它所在脚本的所有协程,对其它脚本里的协程不起作用。
3、IEnumerator类型的函数,不能带ref或out类型参数。
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
//声明一个协程
public IEnumerator Count(int i)
{
while (true)
{
i++;
Debug.Log(i);
yield return null;
}
}
//开启协程的方式1
void Start1()
{
StartCoroutine("Count", 0);
}
//停止协程的方式1
void Stop1()
{
StopCoroutine("Count");
}
//开启协程的方式2
IEnumerator routine;
void Start2()
{
routine = Count(0);
StartCoroutine(routine);
}
//停止协程的方式2
void Stop2()
{
StopCoroutine(coroutine);
}
//开启协程的方式3
Coroutine coroutine;
void Start3()
{
coroutine = StartCoroutine(Count(0));
}
//停止协程的方式3
void Stop3()
{
StopCoroutine(coroutine);
}
void Start()
{
Start3();
}
void Update()
{
if (Input.GetKeyDown("space"))
{
Stop3();
}
}
}