【问题标题】:How to break out of loop in coroutine after some player input? [duplicate]一些玩家输入后如何在协程中跳出循环? [复制]
【发布时间】:2017-05-20 17:14:30
【问题描述】:

我需要的是每隔几秒增加一次玩家的统计数据,并且能够通过按下任何键来中断这个过程。

下面是我的协程。它一直在运行,有什么建议吗?

IEnumerator PlayerAction(PlayerStats playerStats, int incrementor1) 
{
    bool loop = true;
    while (loop)
    {
        if (Input.anyKeyDown)
        {
            loop = false;
            Debug.Log("Action is break");
            yield break;
        }
        else
        {
            yield return new WaitForSeconds(2);
            playerStats.Energy += incrementor1;
            GameClock.Tic++;
            Debug.Log("My first courutine is working!");
        }
    }
}

【问题讨论】:

  • 你研究过停止协程的方法吗?您已经尝试过如何解决这个问题?
  • 是的,我没有找到答案。我将检查移至更新并尝试使用 StopCourutine(),但它看起来是一个糟糕的解决方案。
  • @Kardux OP 想要跳出while 循环,如果您仔细查看`if (Input.anyKeyDown)` 代码。标题错误,但现已修复。
  • 由于您使用yield return,因此问题也可能与您的消费者代码有关。只有当您实际迭代返回的IEnumerator 时,才会执行您的函数代码。你能展示一些吗?
  • @grek40 这个问题已经解决了。那是因为 OP 使用了yield return new WaitForSeconds(2),当if (Input.anyKeyDown) 为真时它会错过帧。在我的回答下查看 OP 的评论。

标签: c# unity3d coroutine ienumerator


【解决方案1】:

我猜你错过了协程中的输入检测,我建议在更新中检测输入并使用变量来检查它,如下所示:

bool isAnyKeyDown = false;//detect is anykeypressed

void Update(){
  if (Input.anyKeyDown){
          isAnyKeyDown = true;
   }

}

IEnumerator PlayerAction(PlayerStats playerStats, int incrementor1) 
{
    bool loop = true;
    while (loop)
    {
        if (isAnyKeyDown)
        {
            loop = false;
            Debug.Log("Action is break");
            StopCoroutine("PlayerAction");
            isAnyKeyDown = false;
            yield break;
        }
        else
        {
            yield return new WaitForSeconds(2);
            playerStats.Energy += incrementor1;
            GameClock.Tic++;
            Debug.Log("My first courutine is working!");
        }
    }
}

【讨论】:

    【解决方案2】:

    它一直在运行,有什么建议吗?

    是的。不要使用yield return new WaitForSeconds 等待。您在此帧期间错过 Input 事件 (if (Input.anyKeyDown))。

    在协程函数中创建计数器的另一种方法是使用Time.deltaTime; 来增加一个变量,然后使用yield return null; 等待,当您使用yield return new WaitForSeconds 时,它只等待一帧而不是几秒钟。

    这就是我上面解释的样子:

    IEnumerator PlayerAction(PlayerStats playerStats, int incrementor1)
    {
        const float secToIncrement = 1f; //When to Increment (Every 1 second)
        float counter = 0;
    
        while (true)
        {
            //Check if we have reached counter
            if (counter > secToIncrement)
            {
                counter = 0f; //Reset Counter
    
                //Increment Player stats
                playerStats.Energy += incrementor1;
                GameClock.Tic++;
                Debug.Log("My first courutine is working!");
    
            }
    
            //Increment counter
            counter += Time.deltaTime;
    
            //Check if we want to exit coroutine
            if (Input.anyKeyDown)
            {
                Debug.Log("Action is break");
                yield break;
            }
    
            //Yield in a while loop to prevent freezing 
            yield return null;
        }
    }
    

    确保使用StartCoroutine 函数调用协程,例如StartCoroutine(PlayerAction(yourPlayerStat,2));

    【讨论】:

    • 是的!柜台正是我需要的,谢谢你的帮助!
    猜你喜欢
    • 2016-04-08
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-14
    • 2017-06-07
    • 2022-01-10
    相关资源
    最近更新 更多