【问题标题】:Ending a coroutine while running in unity3d在 unity3d 中运行时结束协程
【发布时间】:2018-10-12 05:26:21
【问题描述】:

我正在尝试使用按钮启动和结束协程。我可以启动协程但我不能停止它,如果我在第一次启动协程后再次单击按钮,它会再次重新启动并且滑块值上升。

这是我的代码

    public void LoopButton(){

    if (lb == 1){
        StopCoroutine (AutoLoop());
        tb--;
    } else {
        StartCoroutine (AutoLoop ());
        tb++;
    }
}

IEnumerator AutoLoop(){

    slider.value = slider.minValue;

    while(slider.value < slider.maxValue){
        slider.value++;
        yield return new WaitForSeconds(0.5f);
    }

    StartCoroutine (AutoLoop());
}

【问题讨论】:

  • 您应该适当地添加一个“已取消”布尔值,这样您就可以检查 whiles 条件。假设在 Unity 中没有专门的方法来处理这个问题。它确实有点像这里正在发生一些隐式的多任务处理。
  • @Christopher 同意。请注意,通过协程进行的多任务处理只是一个花哨的调度程序,它在 Unity 的同一个主线程中运行 :)
  • @Christopher 太棒了,谢谢大家! :)
  • @Christopher 可能会将其添加为答案。我会投票给你:)
  • 我认为有一种特定于 Unity 的方法来处理这个问题,所以我添加了一个答案。 @Christopher 我还在我的帖子中包含了您的建议作为替代答案。

标签: c# loops unity3d coroutine


【解决方案1】:

您需要调用StopCoroutine 并引用StartCoroutine 返回的相同 Coroutine,如下所示:

private Coroutine loopCoroutine;

public void LoopButton()
{
    if (lb == 1)
    {
        StopCoroutine(loopCoroutine);
        tb--;
    }
    else
    {
        loopCoroutine = StartCoroutine(AutoLoop());
        tb++;
    }
}

要使用这种方法,请将您的 AutoLoop 方法更改为使用 while 循环,而不是在方法结束时启动另一个 AutoLoop 协程。否则,您将无法停止这个在AutoLoop 末尾启动的新协程。

IEnumerator AutoLoop()
{
    while(true)
    {
        slider.value = slider.minValue;

        while (slider.value < slider.maxValue)
        {
            slider.value++;
            yield return new WaitForSeconds(0.5f);
        }
    }
}

对于另一种解决方案,正如另一位用户评论的那样,也可以通过布尔标志停止协程:

private bool stopLoop;

public void LoopButton()
{
    if (lb == 1)
    {
        stopLoop = true;
        tb--;
    }
    else
    {
        stopLoop = false;
        StartCoroutine (AutoLoop ());
        tb++;
    }
}

IEnumerator AutoLoop()
{
    slider.value = slider.minValue;

    while (slider.value < slider.maxValue && !stopLoop)
    {
        slider.value++;
        yield return new WaitForSeconds(0.5f);
    }

    if (!stopLoop)
    {
        StartCoroutine(AutoLoop());
    }
}

但是,使用 Unity 的 StopCoroutine 比使用布尔标志更可取,以提高可读性和简洁性。

【讨论】:

  • 我的理解是,使用布尔标志允许协程进行它可能需要的任何类型的清理,例如如果需要关闭文件访问。
  • @Immersive:这种清理应该留给 finally 块,一种或另一种方式。 finallies 甚至应该在“ThreadAborted”异常上运行。这方面的破坏,他们应该总是逃跑。以下是我经常链接的两篇关于该主题的文章:blogs.msdn.com/b/ericlippert/archive/2008/09/10/… | codeproject.com/Articles/9538/…
  • @Christopher 我原则上同意,但在 Unity 中做起来有点棘手,特别是对于 Unity Coroutines,因为它们在主线程而不是新线程上运行(即没有 ThreadAbortedException) .我对这个问题的细节并不熟悉,但我认为在使用 try/finally 和 StopCoroutine 时需要考虑一些问题。例如,请参阅this Unity forum post: "finally block not executing in a stopped coroutine"
  • @sonny:哦,我只是担心他们会做那么愚蠢的事情。让编译器为您执行协同多任务处理的核心思想是它不会做那么愚蠢的事情。看起来“StopAndDispose()”扩展方法是处理这种情况的方法。
【解决方案2】:

您可以使用StopCoroutine

更多信息在这里: https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html

【讨论】:

    【解决方案3】:

    使用字符串作为协程名称。像这样:

    public void LoopButton(){
    
        if (lb == 1){
            StopCoroutine ("AutoLoop");
            tb--;
        } else {
            StartCoroutine ("AutoLoop");
            tb++;
        }
    }
    
    IEnumerator AutoLoop(){
    
        slider.value = slider.minValue;
    
        while(slider.value < slider.maxValue){
            slider.value++;
            yield return new WaitForSeconds(0.5f);
        }
    
        StartCoroutine ("AutoLoop");
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-25
      • 1970-01-01
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 2022-10-31
      • 1970-01-01
      • 2019-12-18
      • 2021-08-24
      相关资源
      最近更新 更多