【Unity实战】实现强大通用易扩展的对话系统(附项目源码)

文章目录

  • 先看看实现的最终效果
  • 前言
  • 素材
  • 前期准备工作
    • 1. 简单绘制地形
    • 2. 绘制对话框
    • 3. 配置人物动画
    • 4. 实现简单的控制人物移动
  • 控制对话框的显示隐藏
  • 定义对话内容
  • 实现简单的对话功能
  • 逐字打印效果
  • 按下按键快速显示文本
  • 实现多个NPC配置不同对话
  • 扩展
    • TextAsset 读取文档文件
    • 实际应用
  • 补充
  • 源码
  • 参考
  • 完结

先看看实现的最终效果

在这里插入图片描述

前言

之前的对话系统因为存在一些错误和原作者不允许我分享,所以被我下架了,而且之前对话系统确实少了一些功能,比如最基本的逐字打印功能,原本来是打算后面补充的。

对话系统在游戏中实现太常见了,所以我又重新去找了一些对话系统的课程进行学习,把实现过程和笔记分享出来,后面肯定会用到。

本文是参考b站麦扣老师比较老的课程了,我已经看完了,后面发现缺失了挺多功能的:

  • 比如扩展性不好,多NPC很难将对话分开
  • 快速显示的实现过于麻烦了
  • 对话框显示在世界坐标,UI无法适配屏幕的变化
  • 文本只支持显示内容,不支持显示角色名称和人物的不同表情变化

所以我改动的地方可能比较多,因为我想实现的是一个通用的对话脚本,可以很方便的对多个NPC绑定不一样的对话内容,当然,麦扣老师的视频链接我会放在文章底部,感兴趣的也可以去看看原版,对照着学习!

素材

素材下载地址:
https://bakudas.itch.io/generic-rpg-pack
在这里插入图片描述

前期准备工作

1. 简单绘制地形

关于TileMap的使用,这里就不再过多介绍了,感兴趣的可以查看我之前的文章:
【Unity小技巧】Unity2D TileMap的探究(最简单,最全面的TileMap使用介绍)
在这里插入图片描述

2. 绘制对话框

在这里插入图片描述

3. 配置人物动画

在这里插入图片描述

4. 实现简单的控制人物移动

新建脚本,简单的控制人物的移动和动画切换

public class Player : MonoBehaviour
{[Header("移动速度")]public float speed;Animator animator;Vector3 movement;void Start(){animator = GetComponent<Animator>();}void Update(){//移动movement = new Vector3(Input.GetAxisRaw("Horizontal") * Time.deltaTime * speed, Input.GetAxisRaw("Vertical") * Time.deltaTime * speed, transform.position.z);transform.Translate(movement);//动画if (movement != Vector3.zero){animator.SetBool("run", true);}else{animator.SetBool("run", false);}//翻面if(movement.x>0){transform.localScale = new Vector3(1, 1, 1);}if(movement.x<0){transform.localScale = new Vector3(-1, 1, 1);}}
}

效果
在这里插入图片描述

控制对话框的显示隐藏

新增脚本TalkButton,控制NPC对话提示和对话框的显示和隐藏

public class TalkButton : MonoBehaviour
{private GameObject tipsButton;//对话提示按钮[Header("对话框")]public GameObject dialogBox;private void OnTriggerEnter2D(Collider2D other){tipsButton = other.transform.Find("对话提示").gameObject;tipsButton.SetActive(true);}private void OnTriggerExit2D(Collider2D other){tipsButton.SetActive(false);dialogBox.SetActive(false);}private void Update(){if (tipsButton != null && tipsButton.activeSelf && Input.GetKeyDown(KeyCode.R)){dialogBox.SetActive(true);}}
}

效果
在这里插入图片描述

定义对话内容

新建DialogNode,定义每段对话的各种属性

// 代表了一个对话节点。
[Serializable]
public class DialogNode
{[Header("角色的名字")]public string name;[Header("角色的头像")]public Sprite sprite;[TextArea, Header("对话的内容")]public string content;
}

新建Dialogue脚本,继承ScriptableObject,这样我们就可以在界面方便的新建各种对话了

// 表示一段对话
[CreateAssetMenu(menuName="创建对话" ,fileName = "对话")]
public class Dialogue : ScriptableObject 
{// 对话节点public DialogNode[] dialogNodes;
}

回到界面,创建各种对话,并配置对话内容
在这里插入图片描述

实现简单的对话功能

定义NPC脚本

public class NPC : MonoBehaviour {[Header("对话内容")]public Dialogue dialogue;
}

给不同NPC挂载不同的对话
在这里插入图片描述
修改TalkButton,获取对应的NPC对话内容,并修改为单例,方便其他地方调用dialogue对话内容

[NonSerialized]
public Dialogue dialogue;//对话内容//单例
public static TalkButton instance;
private void Awake()
{if(instance == null){instance = this;}else{if(instance != this){Destroy(gameObject);}}DontDestroyOnLoad(gameObject);
}private void OnTriggerEnter2D(Collider2D other)
{dialogue = other.GetComponent<NPC>().dialogue;//。。。
}

新增DialogSystem脚本,挂载在对话框上

public class DialogSystem : MonoBehaviour
{private Dialogue dialogue;//对话内容//索引private int index;//对话内容框TextMeshProUGUI dialogueContent;//名称框TextMeshProUGUI dialogueName;//头像框Image dialogueImage;private void Awake() {gameObject.SetActive(false);    }private void OnEnable(){dialogue = TalkButton.instance.dialogue;dialogueContent = transform.Find("内容").GetComponent<TextMeshProUGUI>();dialogueName = transform.Find("名字").GetComponent<TextMeshProUGUI>();dialogueImage = transform.Find("头像").GetComponent<Image>();//设置人物头像保持宽高比,防止压缩变形dialogueImage.preserveAspect = true;index = 0;Play();}private void Update(){if (Input.GetKeyDown(KeyCode.R) && dialogue != null){//对话播放完,关闭对话if (index == dialogue.dialogNodes.Length){gameObject.SetActive(false);index = 0;}else{//开始对话Play();}}}// Play 函数用于开始播放对话。private void Play(){// 获取当前对话节点,并更新索引值。DialogNode node = dialogue.dialogNodes[index++];// 设置对话内容、角色名称和头像dialogueContent.text = node.content;dialogueName.text = node.name;dialogueImage.sprite = node.sprite;}
}

效果
在这里插入图片描述

逐字打印效果

修改DialogSystem,创建携程实现逐字打印效果,为了防止字体发生错乱我们要加判断,每一行执行完成后才可以继续进入下一段对话

[SerializeField, Header("目前逐字打印速度")]
private float textSpeed;bool isDialogue;//是否正在对话private void OnEnable()
{isDialogue = false;// 。。。
}private void Update()
{if (Input.GetKeyDown(KeyCode.R) && dialogue != null){if (!isDialogue){//对话播放完,关闭对话if (index == dialogue.dialogNodes.Length){gameObject.SetActive(false);index = 0;}else{//开始对话Play();}}}
}// Play 函数用于开始播放对话。
private void Play()
{// 获取当前对话节点,并更新索引值。DialogNode node = dialogue.dialogNodes[index++];// 设置对话内容、角色名称和头像// dialogueContent.text = node.content;StartCoroutine(SetTextUI(node));dialogueName.text = node.name;dialogueImage.sprite = node.sprite;
}//逐字打印
IEnumerator SetTextUI(DialogNode node)
{isDialogue = true;dialogueContent.text = "";for (int i = 0; i < node.content.Length; i++){dialogueContent.text += node.content[i];yield return new WaitForSeconds(textSpeed);}isDialogue = false;
}

效果,记得在面板配置textSpeed值,我这里定为0.1
在这里插入图片描述

按下按键快速显示文本

修改DialogSystem,我们通过控制文本播放速度实现

private float startTextSpeed;//开始逐字打印速度
private void OnEnable()
{//...startTextSpeed = textSpeed;
}private void Update()
{if (Input.GetKeyDown(KeyCode.R) && dialogue != null){//如果正在对话,再次按下R,快速显示所有对话if (isDialogue){textSpeed = 0;}else{//回复文本速度textSpeed = startTextSpeed;//对话播放完,关闭对话if (index == dialogue.dialogNodes.Length){gameObject.SetActive(false);index = 0;}else{//开始对话Play();}}}
}

效果
在这里插入图片描述

实现多个NPC配置不同对话

配置多个NPC,给每个NPC配置不同的对话
在这里插入图片描述
最终效果
在这里插入图片描述

扩展

麦扣的课程用的是TextAsset读取txt文本,这种方式因为不方便配置显示角色名称和头像表情变化,所有我放弃了,但是还是补充一下TextAsset的用法,因为他可能在其他地方可以应用

TextAsset 读取文档文件

TextAsset 是把一种某种格式的文件输入到我们的游戏项目当中,然后它可以帮助我们转换这里边的这个文本
它可以支持的类型有:
在这里插入图片描述
它里边也有一个自带的一个参数的方法,就是.text,它会把整个文件转换成一个单独的字符型的数据

实际应用

比如这样的文本
在这里插入图片描述
代码读取文本

public class DialogSystem : MonoBehaviour
{[Header("文本文件")]public TextAsset textFile; // 用于存储对话文本的文本文件public int index; // 对话索引,用于跟踪当前对话位置List<string> textList = new List<string>(); // 存储从文本文件中读取的对话内容的列表void Start(){GetTextFromFile(textFile);}void GetTextFromFile(TextAsset file){var lineData = file.text.Split('\n'); // 将文本文件按行分割foreach (var line in lineData){textList.Add(line); // 将每行对话文本添加到对话内容列表中}}
}

补充

逐字打印的时候,还可以加入一些打字音效,这里我就不加了,留给大家自己补充

源码

https://gitcode.net/unity1/dialoguesystem
在这里插入图片描述

参考

【视频】https://www.bilibili.com/video/BV1WJ411Y71J/

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/191453.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 旋转方阵

public static void main(String[] args) {Scanner scanner new Scanner(System.in);// N阶方阵int n scanner.nextInt();// 构建方阵List<List<Integer>> matrix new ArrayList<>();for (int i 0; i < n; i) {List<Integer> row new ArrayLis…

win10录屏软件大揭秘,谁才是真正的录屏王者?

Windows 10为用户提供了多种强大的录屏工具&#xff0c;无论您是想捕捉游戏精彩瞬间、记录教程&#xff0c;还是制作演示文稿&#xff0c;都有合适的工具可供选择。本文将详细介绍三款win10录屏软件&#xff0c;通过使用这些录屏软件&#xff0c;用户可以方便地录制下电脑屏幕上…

阿里达摩院开源DAMO-YOLO

1.简介 DAMO-YOLO是一个兼顾速度与精度的目标检测框架&#xff0c;其效果超越了目前的一众YOLO系列方法&#xff0c;在实现SOTA的同时&#xff0c;保持了很高的推理速度。DAMO-YOLO是在YOLO框架基础上引入了一系列新技术&#xff0c;对整个检测框架进行了大幅的修改。具体包括…

人工智能基础_机器学习027_L2正则化_岭回归_非稀疏性_原理解读_公式推导---人工智能工作笔记0067

然后我们再来看一下岭回归,也就是第二范数对吧, 他的公式,平方以后,加和然后开平方.L2的公式是 可以看到L2公式,也是有个阿尔法,惩罚项对吧. 可以看到因为L2带有平方,所以他的图形是个圆形 我们可以把L2范数,进行画出来看看 这里我们先看L2的公式,这里我们让 这个公式写成1 …

汽车OBD2蓝牙诊断仪解决方案程序开发

1、因TL718已经为你建立了物理层、数据链层和部分应用层的协议&#xff0c;所以只要OBD2标准应用层协议文本&#xff0c;ISO15031-5 或 SAE J1979&#xff08;这两个协议是相同的内容&#xff09;。 2、TL718诊断接口 1 套或用TL718芯片自建电路。3、家用PC机电脑一台。4、安…

Python 列表List数据复杂操作

一、将列表数据每2个取一个数据添加到新列表中 prov_code [130100000000, 石家庄市, 130200000000, 唐山市, 130300000000, 秦皇岛市, 130400000000,邯郸市,130500000000, 邢台市, 130600000000, 保定市, 130700000000, 张家口市, 130800000000,承德市,130900000000, 沧州市, …

易云维®医院能源管理系统提供多方案实现医院节能计划

德国卫生部长卡尔劳特巴赫采访时说&#xff1a;“如果我们不赶紧采取有效措施&#xff0c;就会&#xff08;有医院&#xff09;倒闭。” 2022年的德国面临能源危机和通胀挑战&#xff0c;医院系统面临的人员和资金压力再次敲响警钟&#xff0c;正陷入举步维艰的处境。德国医院…

compile: version “go1.19“ does not match go tool version “go1.18.1“

** 1 安装了新版本的go后 为什么go version 还是旧版本&#xff1f; ** 如果你已经按照上述步骤安装了新版本的 Go&#xff0c;但 go version 命令仍然显示旧版本&#xff0c;可能是因为你的环境变量设置不正确或未正确生效。你可以尝试以下方法来解决问题&#xff1a; 重新…

Angular 使用教程——基本语法和双向数据绑定

Angular 是一个应用设计框架与开发平台&#xff0c;旨在创建高效而精致的单页面应用 Angular 是一个基于 TypeScript 构建的开发平台。它包括&#xff1a;一个基于组件的框架&#xff0c;用于构建可伸缩的 Web 应用&#xff0c;一组完美集成的库&#xff0c;涵盖各种功能&…

[Android]新建项目使用AppCompatActivity后运行闪退

报错 日志&#xff1a; Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. FATAL EXCEPTION: main Process: com.example.gatestdemol, PID: 26071 java.lang.RuntimeException: Unable to start a…

高频SQL50题(基础题)-5

文章目录 主要内容一.SQL练习题1.602-好友申请&#xff1a;谁有最多的好友代码如下&#xff08;示例&#xff09;: 2.585-2016年的投资代码如下&#xff08;示例&#xff09;: 3.185-部门工资前三高的所有员工代码如下&#xff08;示例&#xff09;: 4.1667-修复表中的名字代码…

Linux 源码包安装

SRPM 包&#xff0c;比 RPM 包多了一个“S”&#xff0c;是“Source”的首字母&#xff0c;所以 SRPM 可直译为“源代码形式的 RPM 包”。也就是说&#xff0c;SRPM 包中不再是经过编译的二进制文件&#xff0c;都是源代码文件。可以这样理解&#xff0c;SRPM 包是软件以源码形…

万宾科技内涝积水监测仪使用效果一览

当一个城市突降暴雨&#xff0c;对城市管理部门来讲首当其中的是防止积水成患。随着城市人口快速增长&#xff0c;基础设施建设也日益受到更多的关注&#xff0c;城市内涝问题频繁增加&#xff0c;会给城市带来严重的经济损失和人员的安全问题。城市生命线工程建设过程中&#…

一文图解爬虫姊妹篇(spider)

—引导语 爬虫&#xff0c;没有一个时代比当前更重视它。一个好的爬虫似乎可以洞穿整个互联网&#xff0c;“来装满自己的胃”。 接上一篇&#xff1a;一文图解爬虫&#xff08;spider&#xff09; 博主已初步对爬虫的“五脏六腑”进行了解剖。虽然俗称“爬虫”&#xff0c;但窃…

Java 并发编程面试题——Condition 接口

目录 1.Condition 接口有什么作用&#xff1f;2.如何使用 Condition&#xff1f;3.Condition 中有哪些常用的方法&#xff1f;4.✨Condition 的底层实现原理是什么&#xff1f;4.1.等待队列4.2.等待4.3.通知 &#xff08;1&#xff09;参考书籍&#xff1a; 《Java 并发编程的艺…

Ubuntu 24.04发布日期以定

导读Ubuntu 的下一个长期支持 (LTS) 版本 Ubuntu 24.04 的最终发布日期已确定&#xff0c;计划于 2024 年 4 月 25 日发布。 Ubuntu 的下一个长期支持 (LTS) 版本 Ubuntu 24.04 的最终发布日期已确定&#xff0c;计划于 2024 年 4 月 25 日发布。 除此之外&#xff0c;Ubuntu…

Q learning

Q learning Q Learning是强化学习算法中的一个经典算法。在一个决策过程中&#xff0c;我们不知道完整的计算模型&#xff0c;所以需要我们去不停的尝试。 算法流程 整体流程如下&#xff1a; Q-table 初始化 第一步是创建 Q-table&#xff0c;作为跟踪每个状态下的每个动作…

从道一云到畅捷通T+通过接口配置打通数据

从道一云到畅捷通T通过接口配置打通数据 接通系统&#xff1a;道一云 在道一云坚实的技术基础上&#xff0c;道一云推出全新升级的2.0产品矩阵&#xff0c;分别是低码平台、智能门户、场景应用。基于云原生底座&#xff0c;为企业提供集智能门户解决网关流量问题、企业微信端的…

TensorFlow学习笔记--(3)张量的常用运算函数

损失函数及求偏导 通过 tf.GradientTape 函数来指定损失函数的变量以及表达式 最后通过 gradient(%损失函数%,%偏导对象%) 来获取求偏导的结果 独热编码 给出一组特征值 来对图像进行分类 可以用独热编码 0的概率是第0种 1的概率是第1种 0的概率是第二种 tf.one_hot(%某标签…

又双叒!宏电5G RedCap工业智能网关获得首个基于RedCap终端场景的华为技术认证

近日&#xff0c;宏电Z2 V20 5G RedCap工业智能网关率先通过华为OpenLab全球开放实验室的系列严格验证流程&#xff0c;完成基于华为RedCap终端场景的兼容性测试&#xff0c;首个获得华为Cloud Open Labs授予的HUAWEI COMPATIBLE证书及其相关认证徽标使用权。 宏电5G RedCap工业…