最终实现效果,一个使用UGUI实现的简单的对话框信息,点击npc出现对话框,点击Continue跳转下一句,直到最后一句点完对话框消失
主要实现思想:
定义一个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挂上对话系统脚本充当管理器,并赋值好相关的引用
在NPC上挂上NPC脚本,并传递好相关的对话信息