在IEnumerator中切换保持循环

时间:2017-09-28 04:48:02

标签: c# unity3d

嗨大家好我有这个2D小家伙有2个状态" IsSpeaking"和#34;沉默"我使用它们来使Animator设置为真或假的bool,而角色似乎在说话。

我需要IsSpeaking持续不同的时间,具体取决于屏幕上显示的文字数量,如下所示:

Text dialogueNumber(X) appears
Animate Speaking
Wait "X" time...
Animate Idle
Wait in Idle for next text (dialogueNumber) to appear and restart cycle...

我试着用这个小代码做到这一点:

void Update () {
 StartCoroutine(IsSpeaking());
}

IEnumerator IsSpeaking()
{
    switch (dialogueNumber)
    {
        case 0:

            yield return null;                              

            break;        

        case 1:

            functionsScript.IsSpeaking();
            yield return new WaitForSeconds(3);
            functionsScript.Silence();                
            yield break;                

        case 2:

            functionsScript.IsSpeaking();
            yield return new WaitForSeconds(6);
            functionsScript.Silence();                
            yield break;
    }
    yield break;

因此,文本越长,等待时间切换到静音动画的时间越长,但第一次(情况1)似乎正常工作,并且在进入静音之后,它会继续从IsSpeaking到Silence随机来回,我不确定这是否是实现这一目标的最佳方式,或者是否有更好的方式在状态之间切换并等待一段时间?

非常感谢您的建议...

3 个答案:

答案 0 :(得分:5)

您正在IsSpeaking函数中的每一帧调用Update,这意味着即使另一个因WaitForSeconds而尚未完成,它也会一遍又一遍地启动。您当前的代码可以在主题时间内生成超过400个协程,并且还会尝试"说"和#34;沉默"同时。

您可以使用简单的布尔变量来解决该问题。

bool speaking = false;

void Update()
{
    //Run only if not running
    if (!speaking)
        StartCoroutine(IsSpeaking());

}

然后在断开协程中的switch语句之前将布尔变量设置为false

IEnumerator IsSpeaking()
{
    speaking = true;

    switch (dialogueNumber)
    {
        case 0:

            yield return null;

            speaking = false;
            break;

        case 1:

            functionsScript.IsSpeaking();
            yield return new WaitForSeconds(3);
            functionsScript.Silence();

            speaking = false;
            yield break;

        case 2:

            functionsScript.IsSpeaking();
            yield return new WaitForSeconds(6);
            functionsScript.Silence();

            speaking = false;
            yield break;
    }
    yield break;
}

答案 1 :(得分:1)

让玩家决定下一个对话何时出现会不会更好? 不是每个人都读取相同的速度。

沿线的某些事情(希望这不是在错误的轨道上):

while(!ExitDialogue)
{
    animation.Play("Idle");
    yield return StartCoroutine(IdleUntilNext()); //waits for player to press the defined button _keyCode_
    diaNumber++;
    animation.Stop("Idle");
    animation.Play("Speak");
    StartCoroutine(SpeakDialogue(diaNumber)); //wait for X seconds depending on diaNumber before stopping the animation
    animation.Stop("Speak");

}


IEnumerator SpeakDialogue(int diaNumber)
{
    switch (diaNumber)
    {
        case 1:
            yield return new WaitForSeconds(3);
            yield break;
        case 2:
            yield return new WaitForSeconds(6);
            yield break;
        default:
            ExitDialogue = true;
            yield break;
    }


}

IEnumerator IdleUntilNext()
{
    while(!Input.GetKeyDown(_keyCode_))
    {
        yield return null;
    }   
}

答案 2 :(得分:0)

确实我的问题有一个糟糕的方法,更容易在更新功能之外做这个,结果更容易在同一个“下一步”按钮中设置数字作为On Click()内部调用的函数导致某事像这样:

     public void TextID()
       {
         textID= (int)VD.nodeData.extraVars["cuadro"];
         print(textID);

             switch (textID)
             {
               case 0:
               break;

               case 1:
               StartCoroutine(LipsMoving(3));
               break;

               case 2:
               StartCoroutine(LipsMoving(6));
               break;
             }

        }

        IEnumerator LipsMoving(int talkTime)
         {
          funcionesScript.Speaking();
          yield return new WaitForSeconds(talkTime);
          funcionesScript.Idle();

          yield return null;
         }

通过这种方式,我可以在用户单击按钮时获取帧ID,并且还可以在没有奇怪循环的情况下运行我的协同程序。 再次感谢您的帮助和耐心,让您有不同的观点来寻找合适的方式令人耳目一新,希望这对您们有用