首页 > 解决方案 > 当我在 Unity 游戏中的对话之间变化太快时,会出现奇怪的角色

问题描述

我对编码还很陌生(过去 4 个月一直在学习),并且我一直在 Unity 中使用类似 RPG 的对话系统制作 2D 点按游戏,并且对话在大多数情况下都运行良好,除了一件事:每当我从一个对象的对话转到另一个对象的对话时,如果我在它们之间转换得太快,就会开始出现奇怪的字符并且文本被屠杀。

这是我的意思的一个例子:https ://media.giphy.com/media/4QsoxLSInXN0vKciaW/giphy.gif 。.文本是西班牙语,但我认为任何人都可以看到文本的行为不应该像它应该的那样(符号和字母随机组合的奇怪)。我第一次打开两个对话(第一个对话在抽屉对象中,第二个对话在灯对象中)它们都很好,但是第二次我在灯对象中打开对话太快并且使文本看起来很奇怪.

我的代码的对话系统基于 youtube 频道 Brackeys 中显示的系统:https ://www.youtube.com/watch?v=_nRzoTzeyxU 。我修改了这个脚本,以便它可以适应我的游戏,但主要是为了让我可以触发与 UI 按钮的对话并添加一个关闭按钮(这就是为什么一些公共变量可能看起来没有必要但我在其他 UI 中使用它们的原因纽扣)。

这是主要代码:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 
 public class DialogueManager : MonoBehaviour
 {
 
     public Text nameText;
     public Text dialogueText;
     public GameObject gameObject;
     public float delay = 0.5f;
     public PlayerController playerController;
     public Toggle myToggle;
     public GameObject endObject;
 
     private Queue<string> sentences;
 
     // Start is called before the first frame update
     void Start()
     {
         sentences = new Queue<string>();
         
     }
 
     public void StartDialogue(Dialogue dialogue){
 
         playerController.enabled = false;
         nameText.text = dialogue.name;
 
         sentences.Clear();
 
         foreach(string sentence in dialogue.sentences){
             sentences.Enqueue(sentence);
         }
 
         DisplayNextSentence();
     }
 
     public void DisplayNextSentence(){
         if(sentences.Count == 0){
             EndDialogue();
             return;
         }
 
         string sentence = sentences.Dequeue();
         StopAllCoroutines();
         StartCoroutine(TypeSentence(sentence));
     }
 
     IEnumerator TypeSentence(string sentence){
         dialogueText.text = "";
         foreach(char letter in sentence.ToCharArray()){
             dialogueText.text += letter;
             yield return new WaitForSeconds(delay);
         }
     }
 
     void EndDialogue(){
         myToggle.isOn = false;
         endObject.SetActive(false);
         playerController.enabled = true;
         gameObject.SetActive(false);
     }
 
 }

它使用一个包含名为“dialogue”的 Dialogue 的公共类:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 
 [System.Serializable]
 public class Dialogue
 {
     public string name;
     
     [TextArea(3, 10)]
     public string[] sentences;
 }

它还使用了一个通过按钮调用的 Trigger 函数。

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class DialogueTrigger : MonoBehaviour
 {
     public Dialogue dialogue;
     public DialogueManager dialogueManager;
 
     public void TriggerDialogue(){
         dialogueManager.StartDialogue(dialogue);
     }
 }

如果我没有很好地解释自己,我真的很抱歉,就像我说我对这个有点陌生并且还在学习,所以如果你不明白我在问什么或者你想让我澄清一些事情就问我这样我们才能更好地了解彼此。提前感谢任何愿意提供帮助的人!:)

标签: unity3ddialog2d

解决方案


StopCoroutine 相当不可靠,您可以进行布尔检查以查看对话是否正在运行,例如private bool DialogueRunning并将其设置为 true

IEnumerator TypeSentence(string sentence){
     dialogueText.text = "";
      DialogueRunning = true;
     foreach(char letter in sentence.ToCharArray()){
         dialogueText.text += letter;
         yield return new WaitForSeconds(delay);
     }
      DialogueRunning = false;
 }

然后,当您尝试 EndDialogue() 时,首先检查对话是否已完成,如果未完成则返回。否则,您可以将您的设置delay为 0 以立即输入文本,然后结束对话。这将确保协程不会被多次调用。

void EndDialogue(){
if (DialogueRunning) return;

     myToggle.isOn = false;
     endObject.SetActive(false);
     playerController.enabled = true;
     gameObject.SetActive(false);
 }

问题是您有多个对象访问您的text box,但只有一个文本框可以传递值。当协程启动而另一个未完成时,两个都Coroutines将值传递给文本框,而您会得到这个乱七八糟的乱码的句子。

否则你也可以使用 async 来等待任务完成,这使得它比协程更干净一些


推荐阅读