首页 > 解决方案 > 如何使用对话名称作为触发器来开始对话,而不是使用索引?

问题描述

在管理器脚本中,我有一个启动对话名称的方法:StartDialogue:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DialogueManager : MonoBehaviour
{
    public Text dialogueText;
    public Text nameText;
    public float sentencesSwitchDuration;
    public bool animateSentenceChars = false;
    public GameObject canvas;
    public static bool dialogueEnded = false;
    public DialogueTrigger trigger;

    private Queue<string> sentence;

    // Use this for initialization
    void Start()
    {
        sentence = new Queue<string>();
    }

    public void StartDialogue(Dialogue dialogue)
    {
        canvas.SetActive(true);

        nameText.text = dialogue.name;

        sentence.Clear();
        foreach (string sentence in dialogue.sentences)
        {
            this.sentence.Enqueue(sentence);
        }

        DisplayNextSentence();
    }

    public void DisplayNextSentence()
    {
        if (this.sentence.Count == 0)
        {
            EndDialogue();
            return;
        }

        string sentence = this.sentence.Dequeue();
        dialogueText.text = sentence;

        StopAllCoroutines();
        StartCoroutine(DisplayNextSentenceWithDelay(sentence));
    }

    public IEnumerator DisplayNextSentenceWithDelay(string sentence)
    {
        if (animateSentenceChars)
        {
            dialogueText.text = "";
            foreach (char letter in sentence.ToCharArray())
            {
                dialogueText.text += letter;
                yield return null;
            }
        }

        yield return new WaitForSeconds(sentencesSwitchDuration);
        DisplayNextSentence();
    }

    private void EndDialogue()
    {
        dialogueEnded = true;
        if (trigger.dialogueNum == trigger.conversations[trigger.dialogueIndex].Dialogues.Count)
            canvas.SetActive(false);
        Debug.Log("End of conversation.");
    }
}

然后在触发脚本中,我有一个获取索引号的方法名称 TriggerDialogue。例如索引 0 它将开始第一次对话的对话。但实际上它只是从对话列表开始第一​​个对话。

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class DialogueTrigger : MonoBehaviour
{
    public List<Conversation> conversations = new List<Conversation>();
    //public List<Dialogue> dialogue = new List<Dialogue>();

    [HideInInspector]
    public int dialogueNum = 0;

    [HideInInspector]
    public int dialogueIndex = 0;

    private bool triggered = false;
    private List<Dialogue> oldDialogue;
    private bool activateButton = false;

    public void TriggerDialogue(int dialogueIndex)
    {
        this.dialogueIndex = dialogueIndex;

        if (conversations.Count > 0 &&
            conversations[dialogueIndex].Dialogues.Count > 0)
        {
            if (triggered == false)
            {
                if (FindObjectOfType<DialogueManager>() != null)
                {
                    FindObjectOfType<DialogueManager>().StartDialogue(conversations[dialogueIndex].Dialogues[dialogueNum]);
                    dialogueNum += 1;
                }
                triggered = true;
            }
        }
    }

    private void Update()
    {
        ButtonActivation();

        if (DialogueManager.dialogueEnded == true)
        {
            if (dialogueNum == conversations[dialogueIndex].Dialogues.Count)
            {
                return;
            }
            else
            {
                FindObjectOfType<DialogueManager>().StartDialogue(conversations[dialogueIndex].Dialogues[dialogueNum]);
                DialogueManager.dialogueEnded = false;
                dialogueNum += 1;
            }
        }
    }

    public bool ActivateButton()
    {
        return activateButton;
    }

    private void ButtonActivation()
    {
        if (ConversationsChecks() == true)
        {
            foreach (string sentence in conversations[dialogueIndex].Dialogues[dialogueNum].sentences)
            {
                if (sentence != "")
                {
                    activateButton = true;
                }
                else
                {
                    activateButton = false;
                }
            }
        }
        else
        {
            activateButton = false;
        }
    }

    public void SaveConversations()
    {
        string jsonTransform = JsonHelper.ToJson(conversations.ToArray(), true);
        File.WriteAllText(@"d:\json.txt", jsonTransform);
    }

    public void LoadConversations()
    {
        string jsonTransform = File.ReadAllText(@"d:\json.txt");
        conversations.Clear();
        conversations.AddRange(JsonHelper.FromJson<Conversation>(jsonTransform));
    }

    private bool ConversationsChecks()
    {
        bool IsConversationsReady = false;

        if (conversations.Count > 0 &&
            conversations[dialogueIndex].Dialogues.Count > 0 &&
            conversations[dialogueIndex].Dialogues[dialogueNum].sentences.Count > 0 &&
            conversations[dialogueIndex].Dialogues[dialogueNum].name != "" &&
            conversations[dialogueIndex].name != "")
        {
            IsConversationsReady = true;
        }
        else
        {
            IsConversationsReady = false;
        }

        return IsConversationsReady;
    }
}

然后我还有两个小班:

对话:

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

[System.Serializable]
public class Dialogue
{
    [Tooltip("Dialogue Name")]
    public string name;

    [TextArea(1, 10)]
    public List<string> sentences = new List<string>();
}

和对话:

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

[System.Serializable]
public class Conversation
{
    [Tooltip("Conversation Name")]
    public string name;

    public List<Dialogue> Dialogues = new List<Dialogue>();
}

因此,现在当我想开始对话时,我正在调用 TriggerDialogue 方法,如下例所示:

dialogueTrigger.TriggerDialogue(0);

相反,我想做这样的事情:

dialogueTrigger.StartConversation("Opening Scene");

或者

dialogueTrigger.StartConversation("The last conversation");

这是对话和对话检查员的示例截图:

对话

因此,例如,如果我想在游戏中的某个地方开始第一次对话,我会这样做:

dialogueTrigger.StartConversation("The Opening");

它将开始“开场”对话中的对话。

使用索引工作正常,但我想用对话名称开始对话会更容易。

标签: c#unity3d

解决方案


鉴于您正在使用 a List<T>,如果您不再使用索引来获取所需的项目,则每次都需要枚举集合以找到相同的项目。您可以在这里做的最好的事情是将数据结构更改为 a Dictionary,这样您就可以通过 Key 搜索它并避免性能下降。为了避免记住你在对话中输入的名字,也许最​​好使用枚举。

因此,创建枚举:

public enum SceneConversations
{
    OpeningScene = 1,
    // ...
}

并开始使用

public class DialogueTrigger : MonoBehaviour
{
    public Dictionary<SceneConversations, Conversation> conversations = new Dictionary<SceneConversations, Conversation>();

然后你可以使用

public void StartConversation(SceneConversations conversationWanted) {}

并调用它

dialogueTrigger.StartConversation(SceneConversations.OpeningScene);

如果我没记错的话,这还有一个额外的好处,即 Unity 会向您显示 SceneConversations 的可能值的下拉列表,因此这也更容易处理。


推荐阅读