如果我使用一层yield return
,则StopCoroutine()
可以成功停止我的协程。请参见下面的代码示例...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestStopcoroutine : MonoBehaviour {
IEnumerator co = null;
// Use this for initialization
void Start () {
co = FunA();
StartCoroutine(co);
}
private IEnumerator FunA() {
Debug.Log("Enter FunA...");
yield return RepeatPrint();
Debug.Log("FunA end...");
}
private IEnumerator RepeatPrint() {
for (int i = 0; i < 5; i++) {
Debug.Log(i);
yield return new WaitForSeconds(1);
}
}
/// <summary>
/// Set this function to a button on UI Canvas
/// </summary>
public void OnCancelButtonClick() {
if (co != null) {
StopCoroutine(co);
Debug.Log("Stop Coroutine...");
co = null;
}
}
}
此输出为...
// Enter FunA...
// 0
// 1
// 2
// 3
// Stop Coroutine...
但是,如果我添加一层(即FunB()
),FunA()
将停止,但内部协程(FunB()
)不会停止。请参见下面的示例代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestStopcoroutine : MonoBehaviour {
IEnumerator co = null;
void Start () {
co = FunA();
StartCoroutine(co);
}
private IEnumerator FunA() {
Debug.Log("Enter FunA...");
yield return FunB();
Debug.Log("FunA end...");
}
private IEnumerator FunB () {
Debug.Log("Enter FunB...");
yield return RepeatPrint();
Debug.Log("FunB end...");
}
private IEnumerator RepeatPrint() {
for (int i = 0; i < 5; i++) {
Debug.Log(i);
yield return new WaitForSeconds(1);
}
}
/// <summary>
/// Set this function to a button on UI Canvas
/// </summary>
public void OnCancelButtonClick() {
if (co != null) {
StopCoroutine(co);
Debug.Log("Stop Coroutine...");
co = null;
}
}
}
此输出为...
// Enter FunA...
// Enter FunB...
// 0
// 1
// 2
// Stop Coroutine...
// 3
// 4
// FunB end...
因此,我想知道为什么StopCoroutine()
无法成功停止多层yield return
协程?
答案 0 :(得分:1)
对于第二个代码,日志确实应该以{{1}}结尾。
为何显示当前输出有三种可能性:(很可能是这种情况发生的原因)
1 。您正在将Stop Coroutine....
设置为Time.timeScale
。在整个项目中进行搜索,并确保您没有执行此操作:0
。这可能会暂停或唤醒Time.timeScale = 0;
正在等待的协程函数。如果这样做,请暂时将其删除或注释掉,看看是否是问题所在。
2 。您的项目已损坏,现在有一个错误。有时,Unity项目中可能会随机发生一个错误,并且修复该错误的唯一方法是创建一个新项目,然后将资源从旧项目手动移至新项目。
创建一个新项目并在下面测试修改后的代码。
3 。 Unity本身的错误。由于您使用的是 Unity 5.6.4p3 ,因此很有可能是Unity的错误。如果执行#1 和#2 中的操作不能解决您的问题,则只需将Unity更新到最新版本(Unity 2018.xxx)。这样更有可能解决您的问题,并且别忘了用新项目进行测试,而不是导入旧项目。
使用下面问题中的修改后的代码来测试#2 和#3 。它使用WaitForSeconds
函数在一秒后停止协程。
Invoke
预期输出:
IEnumerator co = null;
void Start()
{
co = FunA();
Invoke("OnCancelButtonClick", 1f);
StartCoroutine(co);
}
private IEnumerator FunA()
{
Debug.Log("Enter FunA...");
yield return FunB();
Debug.Log("FunA end...");
}
private IEnumerator FunB()
{
Debug.Log("Enter FunB...");
yield return RepeatPrint();
Debug.Log("FunB end...");
}
private IEnumerator RepeatPrint()
{
for (int i = 0; i < 5; i++)
{
Debug.Log(i);
yield return new WaitForSeconds(1);
}
}
/// <summary>
/// Set this function to a button on UI Canvas
/// </summary>
public void OnCancelButtonClick()
{
if (co != null)
{
StopCoroutine(co);
Debug.Log("Stop Coroutine...");
co = null;
}
}
要解决KYL3R's的回答,即停止主协程不会影响任何其他已经启动的协程。这部分是正确的,但完全取决于协程的启动方式和启动位置。
有两种方法可以启动协程功能:
1 。从Enter FunA...
Enter FunB...
0
Stop Coroutine...
函数的任何函数(例如返回类型为StartCoroutine
的函数)开始使用协程。
void
或
void Start()
{
StartCoroutine(RepeatPrint());
}
2 。通过产生要启动的协程函数,不启动IEnumerator Start()
{
yield return StartCoroutine(RepeatPrint());
}
函数的协程函数。这必须在协程函数或返回类型为StartCoroutine
的函数内完成。无法使用IEnumerator
之类的普通函数来完成。
void
当您从IEnumerator Start()
{
yield return RepeatPrint();
}
开始协程,然后从StartCoroutine
开始子协程,但又杀死了父协程时,子协程功能将并且应该继续以保持原样运行
现在,当您使用StartCoroutine
函数开始使用StartCoroutine
进行协程时,然后使用yield return YourCoroutine()
函数使用StartCoroutine
无来启动子协程,然后杀死父协程,儿童协程将立即并且应该终止或停止,作为父级。
大多数Unity用户不知道并不奇怪,因为它没有记录,但是在Unity中使用协程时,了解这一点非常重要。
答案 1 :(得分:0)
协程彼此独立运行。因此,停止主协同程序不会影响其他已经启动的协同程序。
似乎您有2个选择:
A:Stop the nested Coroutine from inside the first level
RepeatPrint
的引用,并使用 that 通过StopCoroutine停止引用。编辑:实际上没有必要“从第一级内部”,只需使用正确的参考即可。
B:Stop ALL Coroutines in your MonoBehaviour