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

这篇具有很好参考价值的文章主要介绍了【Unity实战】实现强大通用易扩展的对话系统(附项目源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先看看实现的最终效果

unity 对话系统,# unity实战,unity,游戏引擎,游戏

前言

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

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

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

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

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

素材

素材下载地址:
https://bakudas.itch.io/generic-rpg-pack
unity 对话系统,# unity实战,unity,游戏引擎,游戏

前期准备工作

1. 简单绘制地形

关于TileMap的使用,这里就不再过多介绍了,感兴趣的可以查看我之前的文章:
【Unity小技巧】Unity2D TileMap的探究(最简单,最全面的TileMap使用介绍)
unity 对话系统,# unity实战,unity,游戏引擎,游戏

2. 绘制对话框

unity 对话系统,# unity实战,unity,游戏引擎,游戏

3. 配置人物动画

unity 对话系统,# unity实战,unity,游戏引擎,游戏

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);
        }
    }
}

效果
unity 对话系统,# unity实战,unity,游戏引擎,游戏

控制对话框的显示隐藏

新增脚本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);
        }
    }
}

效果
unity 对话系统,# unity实战,unity,游戏引擎,游戏

定义对话内容

新建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;
}

回到界面,创建各种对话,并配置对话内容
unity 对话系统,# unity实战,unity,游戏引擎,游戏

实现简单的对话功能

定义NPC脚本

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

给不同NPC挂载不同的对话
unity 对话系统,# unity实战,unity,游戏引擎,游戏
修改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;
    }
}

效果
unity 对话系统,# unity实战,unity,游戏引擎,游戏

逐字打印效果

修改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
unity 对话系统,# unity实战,unity,游戏引擎,游戏

按下按键快速显示文本

修改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();
            }
        }
    }
}

效果
unity 对话系统,# unity实战,unity,游戏引擎,游戏

实现多个NPC配置不同对话

配置多个NPC,给每个NPC配置不同的对话
unity 对话系统,# unity实战,unity,游戏引擎,游戏
最终效果
unity 对话系统,# unity实战,unity,游戏引擎,游戏

扩展

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

TextAsset 读取文档文件

TextAsset 是把一种某种格式的文件输入到我们的游戏项目当中,然后它可以帮助我们转换这里边的这个文本
它可以支持的类型有:
unity 对话系统,# unity实战,unity,游戏引擎,游戏
它里边也有一个自带的一个参数的方法,就是.text,它会把整个文件转换成一个单独的字符型的数据

实际应用

比如这样的文本
unity 对话系统,# unity实战,unity,游戏引擎,游戏
代码读取文本

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); // 将每行对话文本添加到对话内容列表中
        }
    }
}

修改字体样式(2023/12/26补充)

最近有小伙伴来找我,说实现修改某些字体颜色或者突出某些文本如何做?
其实也很简单,如下,这里就再补充一下。
unity 对话系统,# unity实战,unity,游戏引擎,游戏

这种语法叫做 Rich Text 标记,在 Unity 中可以用于富文本显示。除了 标记外,还有其他一些标记可以用于修改文本的样式、大小、字体等,比如:

<color=red>红色</color>
<color=#FF0000>红色</color>
<color=rgb(255,0,0)>红色</color>

<b>加粗</b>
<i>斜体</i>
<size=30>大号</size>

代码控制

// 使用 Rich Text 标记修改文本内容
myText.text = "这是一段 <color=red>红色</color> 的文本,<b>加粗</b>并且变为 <size=30>大号</size> 字体。";

// 改变文本字体
Font myFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
myText.font = myFont;

这里我们要修改某段对话的文字样式,就很简单了
unity 对话系统,# unity实战,unity,游戏引擎,游戏

补充

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

源码

https://gitcode.net/unity1/dialoguesystem
unity 对话系统,# unity实战,unity,游戏引擎,游戏

参考

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

完结

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

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

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
unity 对话系统,# unity实战,unity,游戏引擎,游戏文章来源地址https://www.toymoban.com/news/detail-752207.html

到了这里,关于【Unity实战】实现强大通用易扩展的对话系统(附项目源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具

    随着Unity开发的深入,基本的Unity编辑器界面并不能满足大部分玩家高阶开发的要求。为了提高开发的效率,有针对性的定制化扩展编辑器界面是提高开发效率的不错选择。 今天就给大家带来Unity官方提高的编辑器扩展工具UIToolkit(集成了UIBuilder和UI Debugger等插件)的使用教程。

    2024年02月04日
    浏览(60)
  • 【unity实战】实现一个buff系统(附项目源码)

    参考原视频链接 【视频】:https://www.bilibili.com/video/BV1Xy4y1N7Cb 注意 :本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入 当今大多数游戏都拥有一些形式的Buff系统,利用这种系统可以增强或削弱游戏角色的特定属性。在Unity中,我们可以使用脚本

    2024年02月04日
    浏览(38)
  • 【vue实战项目】通用管理系统:首页

    前言 本文为博主的vue实战小项目系列中的第三篇,很适合后端或者才入门的小伙伴看,一个前端项目从0到1的保姆级教学。前面的内容: 【vue实战项目】通用管理系统:登录页-CSDN博客 【vue实战项目】通用管理系统:封装token操作和网络请求-CSDN博客 【vue实战项目】通用管理

    2024年02月04日
    浏览(45)
  • Unity简单对话系统实现

    思路 :将每段对话分为一个单独的对话模块,每段对话模块拥有自己独有的ID和几句单独的对话,每段对话中自己定义是否含有选择,每个选择拥有与对话模块对应的相同ID(自己决定选择后跳转的对话模块),点击后跳转到对应对话模块,最后有一个用于管理所有对话模块

    2024年04月28日
    浏览(29)
  • 【vue实战项目】通用管理系统:api封装、404页

    前言 本文为博主的vue实战小项目系列中的第三篇,很适合后端或者才入门的小伙伴看,一个前端项目从0到1的保姆级教学。前面的内容: 【vue实战项目】通用管理系统:登录页-CSDN博客 【vue实战项目】通用管理系统:封装token操作和网络请求-CSDN博客 目录 1.api封装 2.404页面

    2024年02月04日
    浏览(54)
  • Unity下的简单DialogSystem对话系统实现(支持多个对话树)

    ​ GitHub 链接 一个简小但是足够满足一定基础的对话系统。 初始设置步骤: 将package文件夹中的DialogSystem2添加到项目之中。 在Hierarchy窗口面板中创建一个空物体(建议命名成DialogSystem),添加代码 DialogSystemManager 和 DialogMissionEventHandler ,并将 DialogMissionEventHandler 拖拽到 DialogS

    2024年02月03日
    浏览(34)
  • 【vue实战项目】通用管理系统:信息列表,信息的编辑和删除

    本文为博主的vue实战小项目系列中的第七篇,很适合后端或者才入门的小伙伴看,一个前端项目从0到1的保姆级教学。前面的内容: 【vue实战项目】通用管理系统:登录页-CSDN博客 【vue实战项目】通用管理系统:封装token操作和网络请求-CSDN博客 【vue实战项目】通用管理系统

    2024年02月03日
    浏览(47)
  • [Unity] 实现ScriptableObject数据同步Excel表格(对话系统数据管理,C# ExcelNPOI)

            在制作游戏中需要管理各种各样的项目资源,其中游戏中的剧情文字也是一种需要管理的资源。自己刚开始接触游戏开发的时候,第一次看MStudio里面的对话系统教学,只讲了怎么写脚本同步UI的设置,并没有讲有什么方式去管理这些对话数据,视频里拿的是txt来演

    2024年02月10日
    浏览(53)
  • ChatGPT人工智能对话系统源码 一款非常强大的AI智能系统 附带完整的搭建教程

    随着人工智能技术的不断发展,对话系统作为人机交互的重要方式,已经成为了各个领域的热门应用。ChatGPT作为一款强大的人工智能对话系统,备受关注。它基于深度学习技术,通过学习大量的语料库,实现了自然语言理解和生成的能力,能够与用户进行智能化的交互。 以

    2024年01月17日
    浏览(61)
  • 【AI项目实战】某语言模型-stable diffusion-vits-cqhttp 实现能对话能语音能绘画的Q群机器人

    好久没写文章了,终于想起来我有个博客账号系列。。 项目已开源在github上。 文章已滤敏,一切涉及语言模型名字的内容都以某语言模型代替 提示:AI绘画部分建议6G显存以上。 用于接收群友消息,并回复消息。 基于这种对话式的语言模型,可以对用户的聊天进行响应。

    2024年02月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包