【Unity】自定义2D对话系统

23 小时前(已编辑)
2

【Unity】自定义2D对话系统

最终效果:

准备工作

  • 一个八核十六线程的脑子

  • 一个Unity(最佳版本2022.X) ,DOTween插件(Unity商店免费)

对话数据存储

首先创建一个存储对话数据的可序列化C#类DiaLog,ta用来存储每一个对话

每个对话拥有以下属性:

  • 该对话是谁说的(string Character)

  • 该对话要显示的文本(string comment)

  • 该对话文本的颜色(Color color)

    public class DiaLog
    {
        public string Character, Comment; //Character:人物的名称,Comment:显示的文本
        public Color color; //Color:对话文本颜色
    }

现在我们要创建一个 ScriptableObject类 存储这些对话变成一个完整的故事(Story类)

Story类仅包含一个DiaLog类的集合,用来存储故事中的对话数据

[CreateAssetMenu(fileName = "Story", menuName = "DiaLogSystem/Story", order = 0)] //在Assets下右键的Create菜单下添加一个新的菜单项Story
public class Story : ScriptableObject {
    public List<DiaLog> diaLogs = new List<DiaLog>();

}

现在你可以在Assets下右键->Create->DiaLogSystem->Story以创建一个Story类对象,然后在里面编写剧情,如下图:

显示对话

现在我们做一个对话UI,然后用一个StoryManager处理这对话数据

创建一个Canvas,在Canvas底下创建三个Text:

  • PressKeyContinue 提醒用户按XX键继续对话

  • StoryComment 显示对话的文本

  • StoryName 显示对话中的人物名称

如果你想做个对话框也行 用一个Image铺底

现在我们来思考以下对话系统怎么实现:

  • 1.用一个方法接受Story对象并开启对话

  • 2.遍历Story中的每个DiaLog,打字机效果输出它们的文本并修改文本的颜色

  • 3.每个DiaLog遍历时等待用户按下继续对话键,如果当前对话还没有显示完,则直接显示全部文本,否则遍历下一个DiaLog

用一个字符串变量定义继续对话键,我这里选择键盘上的Z键

接下来,创建一个StoryManager脚本。

首先定义一堆变量:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;//DOTween命名空间
public class StoryManager : MonoBehaviour
{
    public Text StoryName;//对话UI部分的StoryName
    public Text StoryComment;//对话UI部分的StoryComment
    public Text PressKeyContinue;//对话UI部分的PressKeyContinue
    public Story story;//当前Story对象
    public float TypingTime = 0.05f;//打字机速度
    public string ContinueCode = "Z";//继续对话键,便于用户修改热键,我这里使用字符串存储
    KeyCode ContinueKey;//继续对话键的KeyCode

在Start方法中给ContinueCode做一个转化:

void Start(){
    ContinueKey = (KeyCode)Enum.Parse(typeof(KeyCode), ContinueCode);//枚举方法:用枚举名找到枚举值
}

用一个SetStory方法接受Story对象并开启对话:

public void SetStory(Story story)
    {
        this.story = story;
        StartCoroutine(StartStory());
    }

哦我去我们终于要开始写主要部分了

一个协程StartStory,用来显示一个故事(这部分有点难,每句话都写了注释(我去累死我了)

IEnumerator StartStory()
    {
        foreach (DiaLog d in story.diaLogs)
        {
            StoryComment.text = "";//初始化文本
            StoryName.text = d.Character;//对话数据赋值
            StoryComment.color = d.color;//对话数据赋值
            //StoryComment.transform.DOPunchPosition(Vector2.one * 10, 0.5f, 10); 如果你想让你的对话看起来非常用动感,可以加上,我认为效果还行
            Tween t = StoryComment.DOText(d.Comment, TypingTime * d.Comment.Length);//DOTween打字机
            t.SetEase(Ease.Linear);//把dotween自带的缓动取消变成匀速打字,谁家打字还带缓动的()
            while (!Input.GetKeyDown(ContinueKey))//等待用户按下继续键
            {
                yield return null;//累了歇会
            }
            //以下是用户按下继续键之后发生的事
            if (StoryComment.text == d.Comment)//如果用户按下继续键的时候 打字机已经打完字了
            {
                yield return null;//缓一帧 不然可能出现【BIG BUG】 具体原因未知
                PressKeyContinue.gameObject.SetActive(false);//把提示文本关掉
                continue;//continue
            }
            else//如果用户按下继续键的时候 打字机还没打完
            {

                t.Kill();//把打字机关掉
                StoryComment.text = d.Comment;//直接显示所有文字
                PressKeyContinue.gameObject.SetActive(true);//把提示文字开启
                yield return null;
                while (!Input.GetKeyDown(ContinueKey))//等待用户按下继续键
                {
                    yield return null;//再歇会
                }
                yield return null;//缓一帧 不然可能出现【BIG BUG】
                PressKeyContinue.gameObject.SetActive(false);//把提示文本关掉
                continue;//continue
            }
        }
            StoryComment.text = "";//重置
            StoryName.text = "";//重置
    }

在unity中创建空对象StoryManager,挂上这个脚本,把三个Text组件赋值

现在你可以随便整个脚本,比如游戏一开始的时候给StoryManager一个Story试试效果

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

public class FastSetStory : MonoBehaviour
{
    public Story story;
    // Start is called before the first frame update
    void Start()
    {
        StoryManager.Instance.SetStory(story);
        Destroy(gameObject);
    }
}

或者用OnTriggerStay2D,在用户走进触发器区域并且按下对话键的时候触发对话

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

public class OnTriggerSetStoMonoBehaviourlBase
{
    public bool PressZ, pressz = false, into = false, DisAppear = false;//PressZ:true:玩家走进触发器后要按Z才能触发对话 false:与之相反,走进触发器立即触发对话
    //pressz:用户是否按下了Z into:用户是否在触发器内 DisAppear:触发对话后是否销毁自身
    public Story story;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Z) && PressZ && into)
        {
            pressz = true;
        }
    }
    void OnTriggerStay2D(Collider2D collision)
    {
        into = true;
        if (PressZ == false)
        {
            StoryManager.Instance.SetStory(story, true);
           if (DisAppear) Destroy(gameObject);
        }
        else if (pressz)
        {
            StoryManager.Instance.SetStory(story, true);
            pressz = false;
            if (DisAppear) Destroy(gameObject);
        }


    }
    void OnTriggerExit2D(Collider2D collision)
    {
        pressz = false;
        into = false;
    }
}

然后你就能编排你的剧情啦!

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...