【问题标题】:NPC dialog system in UnityUnity中的NPC对话系统
【发布时间】:2019-04-01 07:20:49
【问题描述】:

过去几天我一直在努力让对话系统正常工作,但我遇到了一些问题。第一个问题是我需要在输入文本时按下按钮才能在进入下一个句子之前立即完成,当我尝试它时出现了一些奇怪的错误,所以我恢复了它。我一直遇到的第二个问题是,当我复制 NPC 并更改第二个 NPC 的对话时,他们都只是说第一个 NPC 的对话设置为。

目前,我在玩家的侧面有一个碰撞器,当玩家的侧面碰撞器在按下空格键时接触到 NPC 时,它会触发对话。这是我的代码:

播放器脚本:

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

public class Player : Character
{
    public BasicNPCPrototype NPCPrototype;
    private bool nearNPC = false;

    // Use this for initialization
    protected override void Start()
    {
        // This needs to be here because the Override normally would override the Character Start function so we have this here to tell the Character Start function to go
        base.Start();
    }

    // Update is called once per frame
    protected override void Update() // Because the parent script (The Character script) is using protected virtual update it will Override the local update function (This one) so you have to write protected override to make sure they both run
    {
        // Call the GetInput Function
        GetInput();

        CheckIfNear();

        // This needs to be here because the Override normally would override the Character Update function so we have this here to tell the Character Update function to go
        base.Update();
    }

    void GetInput()
    {
        // If the player is active (playerActive is a protected bool in the "Character" script)
        if(playerActive)
        {
            // Normalize "direction" so moving in both directions won't speed up the character (May not be nessisary when using Input.GetAxis, Needs testing)
            direction = Vector2.zero;

            // Get the horizontal Axis and put in the X value of "direction"
            direction.x = Input.GetAxisRaw("Horizontal");
            // Get the Vertical Axis and put in the Y value of "direction"
            direction.y = Input.GetAxisRaw("Vertical");
        }    
    }

    // When the players trigger collider touches somthing
    void OnTriggerEnter2D(Collider2D collision)
    {
        // Check to see if it has the "NPC" tag
        if(collision.tag == "NPC")
        {
            // Set "nearNPC" bool to tue
            nearNPC = true;             
        }
    }

    // When the players trigger collider exits somthing
    void OnTriggerExit2D(Collider2D collision)
    {
        // Check to see if it has the "NPC" tag
        if (collision.tag == "NPC")
        {
            // Set "nearNPC" bool to false
            nearNPC = false;
        }
    }

    private void CheckIfNear()
    {
        // If nearNPC bool is true
        if (nearNPC == true)
        {
            // If the "Jump" Keybind is press
            if (Input.GetButtonUp("Jump"))
            {
                // Call the Speak function in the NPCPrototype script
                NPCPrototype.Speak();
            }
        }
    }
}

NPC 脚本

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

public class BasicNPCPrototype : MonoBehaviour
{
    public Dialogue dialogue;

    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }

    public void Speak()
    {
        // Call the "StartDialogue" function in the DialogueManager and pass in our dialogue variable
        FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
    }
}

这是我的对话管理器:

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

public class DialogueManager : MonoBehaviour
{
    public float waitBeforeDisable = 1f;
    public GameObject dialogueBox;
    public Text nameText;
    public Text dialogueText;

    public Animator animator;

    private Queue<string> sentences;

    private bool conversationActive = false;

    // Use this for initialization
    void Start()
    {
        //dialogueBox.SetActive(false);
        sentences = new Queue<string>();       
    }

    public void StartDialogue(Dialogue dialogue)
    {

        if (conversationActive == false)
        {
            dialogueBox.SetActive(true);

            conversationActive = true;

            animator.SetBool("isOpen", true);

            nameText.text = dialogue.name;

            sentences.Clear();

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

            DisplayNextSentence();
        }

        if (conversationActive == true)
        {
            DisplayNextSentence();
        }

    }

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

        string sentence = sentences.Dequeue();
        StopAllCoroutines();
        StartCoroutine(TypeSentence(sentence));
    }

    void EndDialogue()
    {
        animator.SetBool("isOpen", false);
        StartCoroutine("DisableDialogueBox");
        conversationActive = false;
    }

    IEnumerator TypeSentence(string sentence)
    {
        dialogueText.text = "";

        foreach (char letter in sentence.ToCharArray())
        {
            dialogueText.text += letter;
            yield return null;
        }
    }

    IEnumerator DisableDialogueBox()
    {
        yield return new WaitForSeconds (waitBeforeDisable);
        dialogueBox.SetActive(false);
    }

}

我是真正的编码新手,如果我能得到一些帮助,那就太好了!如果您对我的问题有任何疑问,请随时提出。

【问题讨论】:

  • 你不应该用前导大写来命名你的字段,NPCPrototype 看起来像一个类名。至少您没有将其声明为 BasicNPCPrototype BasicNPCPrototype;,这会引发实例与静态解析问题。
  • @Draco18s 好的,我会考虑修复它,但你能帮忙吗?
  • 你在哪里设置NPCPrototype的值?
  • @Draco18s 在检查员中

标签: c# unity3d dialog


【解决方案1】:

您没有更改您的 NPCPrototype 参考

你在哪里设置 NPCPrototype 的值? – Draco18s

@Draco18s 在检查器中 – Ultra Gamer

因为你在检查器中设置了它(并且没有其他地方)它永远不会改变。如果你希望对话框来自特定的 NPC,你需要获取组件 来自那个NPC当“我在附近吗?”检查/碰撞。例如:

void OnTriggerEnter2D(Collider2D collision)
{
    // Check to see if it has the "NPC" tag
    if(collision.tag == "NPC")
    {
        // Set "nearNPC" bool to tue
        nearNPC = true;
        NPCPrototype = collision.gameObject.GetComponent<BasicNPCPrototype>();
    }
}

【讨论】:

  • 好的,但是现在两个 NPC 都从他们的第二组句子开始。所以如果要设置的话,第一个是“你好,我叫___”,第二个是“我喜欢周末去钓鱼”。而不是一个接一个地运行,只有第二个播放。有什么解决办法吗?
  • 您有if (conversationActive == false),后跟if (conversationActive == true)。两者都被调用并且是 else 关键字存在的原因。
  • 您需要保存对协程的引用(StartCoroutine() 返回它)并在其上调用StopCoroutine()
  • yield return null; 将协程置于 pause 并稍后在下一条指令处恢复。我建议阅读coroutines
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 2020-02-07
  • 1970-01-01
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多