【问题标题】:How to skip/finish the coroutine instantly?如何立即跳过/完成协程?
【发布时间】:2022-11-15 03:56:32
【问题描述】:

我的游戏中有一个对话系统,最近我发现了如何通过使用协程为对话一个一个添加字母。我想跳过单击屏幕时添加字母的动画,然后立即完成对话。

我这里有一个协程,它循环遍历句子或字符串的字母,并将其显示在我的对话文本对象中。我找不到用于立即完成协程的特定关键字。有没有一种方法可以跳过或立即完成协程,以便在单击对话或单击屏幕时立即完成对话?

显示对话和协程的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;

public class InformantDialogue : MonoBehaviour
{
    // NPC DATA
    private Informant informantJson;
    [SerializeField] TextAsset characterData;

    // DIALOG UI
    [SerializeField] GameObject dialogBox, article;
    [SerializeField] TextMeshProUGUI dialogue;

    // DIALOG CYCLE VARIABLES
    private bool clickEnable;
    private int dialogId, multiDialogCycle;
    public int progress;
    string[] multiDialog;

    private void OnEnable()
    {
        setJSON();
        loadCharacterData();
    }

    void Start()
    {
        dialogId = 1;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0) && clickEnable == true)
        {
            Debug.Log(dialogId);    
            if (multiDialog.Length > 1)
            {
                if (multiDialogCycle == multiDialog.Length - 1)
                {
                    closeDialog();
                    progressDialog();
                }
                else
                {
                    multiDialogCycle++;
                    loadCharacterData();
                }
            }
            else
            {
                closeDialog();
                progressDialog();
            }
        }
    }

    public void loadCharacterData()
    {
        // DIALOGUE
        multiDialog = getIDialog(dialogId).dialog_message.Split('#');

        if (multiDialogCycle == 4)
        {
            article.SetActive(true);
        }

        if (multiDialog.Length == 1)
        {
            //dialogue.text = getIDialog(dialogId).dialog_message;
            StopAllCoroutines();
            StartCoroutine(TypeSentence(getIDialog(dialogId).dialog_message));
        }
        else if (multiDialogCycle < multiDialog.Length)
        {
            //dialogue.text = multiDialog[multiDialogCycle];
            StopAllCoroutines();
            StartCoroutine(TypeSentence(multiDialog[multiDialogCycle]));
            clickEnable = true;
        }
    }

    // INFORMANT DIALOGUE GETTER
    public InformantDialog getIDialog(int dialogId)
    {
        foreach (InformantDialog dialog in informantJson.informant_dialogs)
        {
            if (dialog.id == dialogId)
            {
                return dialog;
            }
        }
        return informantJson.informant_dialogs[0];
    }

    IEnumerator TypeSentence(string sentence)
    {
        dialogue.text = "";
        foreach(char letter in sentence.ToCharArray())
        {
            dialogue.text += letter;
            //yield return null;
            yield return new WaitForSeconds(0.01f);
        }
    }

    private void showDialogue()
    {
        dialogBox.SetActive(true);
    }

    private void closeDialog()
    {
        dialogBox.SetActive(false);
        clickEnable = false;
        multiDialogCycle = 0;
    }

    private void setJSON()
    {
        if (progress == 0)
        {
            characterData = Resources.Load<TextAsset>("JSON/Informant");
        }else if (progress == 1)
        {
            characterData = Resources.Load<TextAsset>("JSON/Informant1");
        }
        else if (progress == 2)
        {
            characterData = Resources.Load<TextAsset>("JSON/Informant2");
        } else
        {
            clickEnable = false;
        }
        informantJson = JsonUtility.FromJson<Informant>(characterData.text);
    }

    private void progressDialog()
    {
        if (dialogId == informantJson.informant_dialogs.Length)
        {
            dialogId = 0;
            progress++;
        }
        dialogId++;
    }
}

【问题讨论】:

  • yield return null; 等待 1 帧(下一帧继续)。如果你只是返回但继续执行循环,它不会等待并“立即”完成。

标签: c# unity3d coroutine


【解决方案1】:
IEnumerator TypeSentence(string sentence)
{
    boolThatStartFalseAndWillBeTrueWhenPlayerClickOnScreen = false;
    dialogue.text = "";
    foreach(char letter in sentence.ToCharArray())
    {
        if (boolThatStartFalseAndWillBeTrueWhenPlayerClickOnScreen)
        {
            dialogue.text = sentence;
            break;
        }
        dialogue.text += letter;
        //yield return null;
        yield return new WaitForSeconds(0.01f);
    }
}

【讨论】:

    【解决方案2】:

    我已经将我的方法添加到协同程序中。我更喜欢保留协程的句柄,并在协程结束时将其置空。因此你可以只重启那个协程。 FinishTypingSentence() 停止它并将整个文本设置在应有的位置。

    string typedSentence;
    private IEnumerator _typeSentenceCoroutine;
    
    //Caching this will save some memory allocation.
    WaitForSeconds waitFor01Seconds = new WaitForSeconds(0.01f);
    
    void StartTypingSentence()
    {
        if (_typeSentenceCoroutine != null) StopCoroutine(_typeSentenceCoroutine);
        _typeSentenceCoroutine = TypeSentence();
        StartCoroutine(_typeSentenceCoroutine);
    }
    public void FinishTypingSentence()
    {
        if (_typeSentenceCoroutine != null) StopCoroutine(_typeSentenceCoroutine);
        _typeSentenceCoroutine = null;
        dialogue.text = typedSentence;
    }
    
    IEnumerator TypeSentence()
    {
        dialogue.text = "";
        foreach (char letter in typedSentence.ToCharArray())
        {
            dialogue.text += letter;
            yield return waitFor01Seconds;
        }
        _typeSentenceCoroutine = null;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多