time:20210909
更新一下这篇文章,现有版本StartCoroutine已经有返回值了,可以自己保存返回值,用于Stop。但是这篇SingleCoroutine还是有意义的。
取决于设计上采用什么样的设计模式。
因为Coroutine有各种开启方法
StartCoroutine(字符串);
StartCoroutine(函数);
StopCoroutine(字符串);
StopCoroutine(函数);
StopAllCoroutines();
用过就会知道 开启和停止的调用比较混乱。
用字符串启动,可以用字符串停止。
用函数启动,无法用函数停止。
1.为了解决这个对应关系,所以可以考虑到Coroutine和MonoBehaviour的特性:
Coroutine是依赖于MonoBehaviour运行的。
GameObject.Active设置为false,可以停止这个GameObject上MonoBehaviour的所有行为。
MonoBehaviour.Enable设置为false,可以停止这个脚本的所有行为。
2.经过测试,发现启动Coroutine可以用MonoBehaviour的子类启动,并不关注IEnumerator函数所在的脚本。
函数所在的脚本被Enable(false)或者Active(false),并不影响启动Coroutine的MonoBehaviour脚本继续跑Coroutine。
所以可以得出结论: Coroutine会跑在启动它的MonoBehaviour脚本上。
所以就有了SingleCoroutine的方案:
其实逻辑很简单,用一个空脚本Attach到GameObject上,用这个GameObject上的MonoBehaviour脚本去启动Coroutine。
那么我们要停止Coroutine,只需要操作这个GameObject或者MonoBehaviour脚本的 enable或者active 就可以了。
在这样的情况下,我们就无所谓启动Coroutine用哪种方法,因为停止Coroutine并不需要找对应的函数,
而是无脑简单的去关脚本就好了。
这个方案有个缺点就是 为了针对一个Coroutine做开关,
所以使用的时候,一个MonoBehaviour只允许启动一个Coroutine。启动多个。。那么停止的时候,就会把起在同一个MonoBehaviour的Coroutine全部停止。
代码如下:
SingleCoroutine类:
public class SingleCoroutine : MonoBehaviour
{
}
SingleCoroutine对象池;
private Queue<SingleCoroutine> m_queueSingleCoroutine = new Queue<SingleCoroutine>();
public SingleCoroutine AcquireSingleCoroutine()
{
SingleCoroutine result = null;
if (m_queueSingleCoroutine.Count > 0)
{
result = m_queueSingleCoroutine.Dequeue();
}
else
{
GameObject newObj = new GameObject();
result = newObj.AddComponent<SingleCoroutine>();
}
result.gameObject.SetActive(true);
return result;
}
public void FreeSingleCoroutine(SingleCoroutine sc)
{
sc.StopAllCoroutines();
sc.gameObject.SetActive(true);
m_queueSingleCoroutine.Enqueue(sc);
}
这边我使用了 sc.gameObject.SetActive(),实际上用MonoBehaviour.Enable也是可以的。用GameObject的原因是因为在面板上比较容易看到 灰色和白色的 Active状态,便于调试。而且对比之下性能差异,基本可以忽略。
测试代码:
private SingleCoroutine m_scUsing = null;
public void BeginCoroutineTest()
{
m_scUsing = AcquireSingleCoroutine();
m_scUsing.StartCoroutine(test());
}
public void EndCoroutineTest()
{
FreeSingleCoroutine(m_scUsing);
}
private IEnumerator test()
{
Debug.Log("1");
yield return new WaitForSeconds(1);
Debug.Log("2");
yield return new WaitForSeconds(1);
Debug.Log("3");
yield return new WaitForSeconds(1);
Debug.Log("4");
yield return new WaitForSeconds(1);
Debug.Log("5");
yield return new WaitForSeconds(1);
Debug.Log("6");
yield return new WaitForSeconds(1);
}
void Update ()
{
if (Input.GetKeyDown(KeyCode.A))
{
BeginCoroutineTest();
}
if (Input.GetKeyDown(KeyCode.S))
{
EndCoroutineTest();
}
}
这里的Demo是一个概念,具体编码和设计方法,可以随意调整。
程序学无止尽。
欢迎大家沟通,有啥不明确的,或者不对的,也可以和我私聊
我的QQ 334524067 神一般的狄狄