Coroutine(协程)作为Unity引擎中的一项有用的特性,在开发中带给我们了很多帮助,但在使用过程中,有一个新人或没有仔细阅读文档的开发者常犯的错误。那就是使用了错误的姿势来StopCoroutine,下面我来进行一番演示:
创建一个脚本:
public class TestCoroutine : MonoBehaviour
{
IEnumerator CoroutineMethod()
{
while (true)
{
Debug.Log("Coroutine is running...");
yield return new WaitForSeconds(1);
}
}
}
有一个每秒打印消息的协程。下面是几种开起的写法:
public void StartCoroutineWithString()
{
StartCoroutine("CoroutineMethod");
}
public void StartCoroutineWithEnumerator1()
{
StartCoroutine(CoroutineMethod());
}
public void StartCoroutineWithEnumerator2()
{
_runningItor = CoroutineMethod();
StartCoroutine(_runningItor);
}
以及几种关闭的写法:
public void StopCoroutineWithString()
{
StopCoroutine("CoroutineMethod");
}
public void StopCoroutineWithEnumerator1()
{
StopCoroutine(CoroutineMethod());
}
public void StopCoroutineWithEnumerator2()
{
if (_runningItor != null)
{
StopCoroutine(_runningItor);
_runningItor = null;
}
}
我使用了一个UI进行测试:
读者可先思考一下每种开起方法的关闭方法...
...
...
...
...
下面公布我的测试结果
StopWIthString | StopWithEnumerator1 | StopWithEnumerator2 | |
StartWithString | YES | NO | NO |
StartWithEnumerator1 | NO | NO | NO |
StartWithEnumerator2 | NO | NO | YES |
有没有一点suprise??没有的话你就是合格的开发者XD。上面的结果表明,以函数名字符串为参数开起的协程,可以用函数名字符串的形式关闭,可以猜想出,在开启时Unity通过反射获取到成员函数,然后将IEnumerator与函数名建立映射。在关闭时用函数名获取IEnumerator,再关闭。StartWithEnumerator2就是该过程最直接的方式,通过IEnumerator来关闭。至于StartWithIEnumerator1为什么不能关闭?因为使用这样的方法:
StopCoroutine(CoroutineMethod());
是向StopCoroutine()传递了一个新的IEnumerator,并不是StartCoroutine()时传递的对象。因此Unity找不到你所指的是哪个协程。
其实Unity推荐的写法上面的都不是,StartCoroutine其实有一个类型是Coroutine的返回值:
public Coroutine StartCoroutine(IEnumerator routine);
public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value);
public Coroutine StartCoroutine(string methodName);
使用public void StopCoroutine(Coroutine routine);
可以关闭任意形式开起的协程。我们来修改下代码,将开起时返回的Coroutine保存下来,并添加一个使用Coroutine的关闭方法:
public void StartCoroutineWithString()
{
_runningCoroutine = StartCoroutine("CoroutineMethod");
}
public void StartCoroutineWithEnumerator1()
{
_runningCoroutine = StartCoroutine(CoroutineMethod());
}
public void StartCoroutineWithEnumerator2()
{
_runningItor = CoroutineMethod();
_runningCoroutine = StartCoroutine(_runningItor);
}
...
...
public void StopCoroutineWithCoroutineObj()
{
if (_runningCoroutine != null)
{
StopCoroutine(_runningCoroutine);
_runningCoroutine = null;
}
}
更新测试UI:
测试结果不出所料:
StopWithString | StopWithEnumerator1 | StopWithEnumerator2 | StopWithCoroutineObj | |
StartWithString | YES | NO | NO | YES |
StartWithEnumerator1 | NO | NO | NO | YES |
StartWithEnumerator2 | NO | NO | YES | YES |
使用Coroutine关闭协程的方式,兼容性广,效率佳,是上上之选!
本博客还很年轻,会不时发布一些Unity开发经验和有用的框架组件。读者有任何问题都可以向作者提问,欢迎大家踊跃参与!大家的鞭笞是我成长的动力!谢谢!