Unity功能模块一对话系统(5)-完善对话流程及功能

       现在我们的文本仍然是单句显示的,这还不是我们想要的效果,本期让我们完善对话流程,并使用SO(ScriptableObject)来进行一段对话序列的配置和动态加载。

最终效果功能展示

功能一:场景内可根据资源序号ID来动态加载对话数据

功能二:按空格进行下一句,如果当前对话未打印完毕,按下空格则快进直接显示全部文本。

功能三:支持对话中可委托触发

这里碍于篇幅我会分析几个类中的部分关键点,关键的功能源码在后文。

一.功能分析

1.DialogueDataSequence

对话数据SO类

职能

创建SO文件,易于配置对话数据。

注意类前需要使用特性[CreateAssetMenu()]

示例代码

[CreateAssetMenu(menuName = "编辑器界面的创建目录", fileName = "创建出的文件的名称")]

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

[CreateAssetMenu(menuName = "Data/DialogueDataLine", fileName = "DialogueDataLine")]
public class DialogueDataSequence : ScriptableObject
{
    [Header("对话线ID")]
    public int ID;
    [Header("自动下一句")]
    public bool canAutonNext;
    [Header("可以快进")]
    public bool canQuickShow;
    [Header("打字机效果")]
    public bool needTyping;
    [Header("当前话语序号")]
    public int currentIndex;
    [Header("淡入时间")]
    public float fadeDuration;
    [Header("对话线")]
    public List<DialogueData> dialogueLine = new List<DialogueData>();
}

[Serializable]
public class DialogueData
{
    [Header("讲述者")]
    public string speaker;
    [Multiline]
    [Header("内容文本")]
    public string content;
}

2.DialoguePanel 

对话框面板

对话框面板无需考虑当前是哪个对话序列,只接收显示的必要信息。

职能

显示一句对话文本信息

关键字段

  [Header("高级文本")]
  public AdvancedText displayText;
  [Header("文本讲述者")]
  public TMP_Text speakerNameText;

  //可以快速显示
  bool _canQuickShow;
  //自动显示下一句
  bool _canAutonNext;

关键函数

  /// <summary>
  /// 显示对话框
  /// </summary>
  /// <param name="speaker">讲述者</param>
  /// <param name="content">内容</param>
  /// <param name="needTyping">使用打字机效果</param>
  /// <param name="fadeDuration">打印间隔</param>
  /// <param name="canQickShow">快速显示</param>
  /// <param name="canAutonNext">自动下一句</param>

  public void ShowDialogue(string speaker, string content, bool needTyping = true, float fadeDuration = 0.2f, bool canQickShow = true, bool canAutonNext = false) 
  {
      speakerNameText.text = speaker;
      speakerNameText.GetComponent<Animator>().SetTrigger("Show");
      
      if (displayText.text != "") 
      {
          displayText.TextDisAppear();
      }

      _canQuickShow = canQickShow;
      _canAutonNext = canAutonNext;

      if (needTyping)
          StartCoroutine(displayText.ShowText(content,E_DisplayType.Typing,fadeDuration));
      else
          StartCoroutine(displayText.ShowText(content,E_DisplayType.Fading,fadeDuration));
  }

3.DialogueManager

对话管理器

职能

1.持有对当前对话序列SO文件的引用。通过外部传入的序列号加载目标对话序列。

2.开启和关闭对话框面板。

3.操作当前的对话序列(如添加对话委托)

关键字段

  [Header("当前进行的对话序列")]
  public DialogueDataSequence currentDialogueSq;

  DialoguePanel D_Panel;//对话面板

功能函数

1.BeginDialogueSequence()

暴露开始对话及开始下一句对话接口,若下一句已经是最后一句,则关闭对话框。

  /// <summary>
  /// 根据对话线的ID开启一段对话
  /// </summary>
  /// <param name="ID">对话线序号</param>
  /// <param name="action">对话委托</param>
  public void BeginDialogueSequence(int ID, Action action = null)
  {
       //加载目标对话序列,获得其引用
       currentDialogueSq = Resources.Load<DialogueDataSequence>("StaticData/DialogueLine/" + ID);
  currentDialogueSq.currentIndex = 0;

      action?.Invoke();//接收对话委托
      UIManager.Instance.ShowPanel<DialoguePanel>(panel =>
      {
//开启对话框,从对话序列的开始显示对话文本内容
          panel.ShowDialogue(currentDialogueSq.dialogueLine[currentDialogueSq.currentIndex].speaker,                                          
                   currentDialogueSq.dialogueLine[currentDialogueSq.currentIndex].content,
                   currentDialogueSq.needTyping, currentDialogueSq.fadeDuration,
                   currentDialogueSq.canQuickShow, currentDialogueSq.canAutonNext);
           D_Panel = panel;
      });
      Debug.Log(currentDialogueSq.currentIndex);
      ActionCheck();
  }


  /// <summary>
  /// 每结束一句对话时检查是否有委托需要执行
  /// </summary>
  void ActionCheck()
  {
      for (int i = 0; i < currentDialogueSq.eventList.Count; i++)
      {
          if (currentDialogueSq.eventList[i].eventIndex == currentDialogueSq.currentIndex)
          {
              currentDialogueSq.eventList[i].MyEvent?.Invoke();
              Debug.Log("检测到对话事件触发!");
          }
      }
  }

2.NextDialogue()

当前对话序列内索引自增,显示下一句对话

  /// <summary>
  /// 用于隐藏当前文本并显示下一句文本,用于外部调用(如面板或按钮)
  /// </summary>
  public IEnumerator NextDialogue()
  {
      if (currentDialogueSq.currentIndex + 1 < currentDialogueSq.dialogueLine.Count)
      {
          currentDialogueSq.currentIndex++;
          D_Panel.ShowDialogue(currentDialogueSq.dialogueLine[currentDialogueSq.currentIndex].speaker,
                                                         currentDialogueSq.dialogueLine[currentDialogueSq.currentIndex].content,
                                                        currentDialogueSq.needTyping, currentDialogueSq.fadeDuration,
                                                        currentDialogueSq.canQuickShow, currentDialogueSq.canAutonNext);
          Debug.Log(currentDialogueSq.currentIndex);
          ActionCheck();
      }
      else
      {
          EndDialogueSquence();//结束对话
      }

      yield return null;
  }


  /// <summary>
  /// 结束一段对话序列
  /// </summary>
  void EndDialogueSquence()
  {
      currentDialogueSq?.eventList.Clear();
      currentDialogueSq = null;
      UIManager.Instance.HidePanel<DialoguePanel>();
  }

//退出游戏重置对话状态
private void OnApplicationQuit()
{
    currentDialogueSq?.eventList.Clear();
    currentDialogueSq = null;
}

       由于我个人框架的实现与UI部分联系密切的问题,考虑给出完整源码文章会过于冗余且侧重点失衡,上面分享的是我实现过程中的关键功能片段,需要朋友们结合实际应用适配到自己的项目中,原理的大致通用的,当然上述代码某些地方肯定是能够进一步优化拓展的,也欢迎大佬不吝赐教。

二.实验结果测试

1.测试脚本

using UnityEngine;
public class TMPTest : MonoBehaviour
{
    [Header("对话序号")]
    public int dialogueID;


    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.E))
        {
            DialogueManager.Instance.BeginDialogueSequence(dialogueID, () =>
            {
                DialogueManager.Instance.AddDialogueEvent(1, 2, T1);
                DialogueManager.Instance.AddDialogueEvent(1, 4, T2);
            });
        }
    }

    void T1()
    {
        Debug.Log("对话内事件1触发");
    }
    void T2()
    {
        Debug.Log("对话内事件2触发");
    }
}

2.数据配置

这里我挂载了测试脚本,并配置了一段对话数据,序号为1

三.实验结果展示

打印效果:

对话中事件触发效果:

三.后文

       由于我个人框架的实现与UI部分联系密切的问题,考虑给出完整源码文章会过于冗余且侧重点失衡,上面分享的是我实现过程中的关键功能片段,需要朋友们结合实际应用适配到自己的项目中,原理的大致通用的,当然上述代码某些地方肯定是能够进一步优化拓展的,也欢迎大佬不吝赐教。

本篇完!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值