Unity3D---模块划分(一)对话系统的简单实现

时间:2022-05-10 08:04:54

最终实现效果,一个使用UGUI实现的简单的对话框信息,点击npc出现对话框,点击Continue跳转下一句,直到最后一句点完对话框消失

Unity3D---模块划分(一)对话系统的简单实现

主要实现思想:

定义一个interactable基类,用于表示响应用户鼠标的点击事件,在interaceable类中注册所有的鼠标管理单例中的事件(鼠标管理单例在上上篇博文中有讲述)所有可交互的物体都继承这个基类,基类定义一个虚方法interace()表示互动,具体的实现交给子类实现,interaceable基类代码如下:

public class Interactable : MonoBehaviour
{
    [HideInInspector]
    public NavMeshAgent playerAgent;

    private bool interacted = true;
    private void Start()
    {
        //注册事件
        MouseManager.Instance.OnLeftClick += MoveToInteraction;
        //获取player的navmesh agent设定目的地让其移动
        playerAgent = GameObject.FindGameObjectWithTag(TagManager.Instance.player).GetComponent<NavMeshAgent>();
    }
    
    
    public virtual void MoveToInteraction(GameObject go)
    {
        if (go == gameObject)
        {
            //点中可交互物品,设定停止距离(防止重叠),设定目的地,标识符更改
            playerAgent.stoppingDistance = 3f;
            playerAgent.destination = this.transform.position;
            interacted = false;
        }
        else
        {
            interacted = true;
        }
    }
    private void Update()
    {
        //判断是否有agent和判断是否正在计算路径
        if (playerAgent != null && !playerAgent.pathPending)
        {
            //判断与目标的距离是否在停止距离之内(是否到达)
            if (playerAgent.remainingDistance <= playerAgent.stoppingDistance)
            {
                if (!interacted)
                {
                    Interact();
                    interacted = true;
                }
            }
        }
    }
    //定义好一个虚互动方法方便子类重写
    public virtual void Interact()
    {
        Debug.Log("base interact!");
    }
}

(二)在游戏中制作对话系统的单例:

这里我用了需要拖到GameObject上的单例模式,因为这种方式只需要定义几个publicd的UI组件,就可以很方便的在inspector面板中拖入我们的UI组件,如果使用那种不需要拖到GameObject上就存在的单例模式会使用大量的find(),GetComponent等等,太繁琐,实现方法很简单这里不细说,下面是主要代码:

public class DialogueSystem : MonoBehaviour
{
    
    #region singleton
    public static DialogueSystem Instance;
    private void Awake()
    {
        Instance = this;
    }
    #endregion


    private List<string> dialogues = new List<string>();
    private string npcName;
    private int index = 0;

    public GameObject dialoguePanel;

    public Button continueBtn;
    public  Text dialogueText, nameText;

    private void Start()
    {
         dialoguePanel.SetActive(false);
         continueBtn.onClick.AddListener(ContinueDialogue);//给btn增加事件调用下一句
    }
    //传入对话
    public void AddNewDialogue(string[] lines,string name)
    {
        //将inspector面板中设定好的对话信息传入
        dialogues = new List<string>(lines.Length);
        foreach (string line in lines)
        {
            dialogues.Add(line);
        }
        //将名字传入
        this.npcName = name;
    }
    //显示对话
    public void CreatDialogue()
    {
        //将数组索引置为0
        index = 0;
        //将数组的第一号元素写入text
        dialogueText.text = dialogues[index];
        //写入名称
        nameText.text = npcName;
        //UI面板激活
        dialoguePanel.SetActive(true);
        //索引指向下一号元素
        index++;
    }
    public void ContinueDialogue()
    {
        //判断索引是否越界
        if (index < dialogues.Count )
        {
            //更新text
            dialogueText.text = dialogues[index];
            //指向下一号元素
            index++;
        }
        else
        {
            dialoguePanel.SetActive(false);
        }
    }
}

(三)继承至interactable的NPC类的代码编写:

重写基类的interace()方法,并定义几个public数组方便在inspector面板中自己添加对话信息

public class NPC : Interactable
{
    public string[] dialogue;//ins拖入引用
    public string NPC_name;//ins拖入引用

    public override void Interact()
    {
        DialogueSystem.Instance.AddNewDialogue(dialogue,NPC_name);//npc响应点击
        DialogueSystem.Instance.CreatDialogue();//完成传入信息后显示对话
    }
}

在场景中添加一个空的game object挂上对话系统脚本充当管理器,并赋值好相关的引用

Unity3D---模块划分(一)对话系统的简单实现

在NPC上挂上NPC脚本,并传递好相关的对话信息

Unity3D---模块划分(一)对话系统的简单实现