【Unity3D小功能】Unity3D中UGUI-Text实现打字机效果

news2024/11/27 8:23:07

推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址
  • QQ群:398291828

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

需求要实现Text的打字机效果,一看居然还没这类型的教程,遂补上。

二、实现

2-1、使用DOTween插件实现效果

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class TextWriterDoTween : MonoBehaviour
{
    private void Start()
    {
        DoTweenText("123456", 6, () => 
        {
            Debug.Log("用6秒显示6个字");
        });
    }
    /// <summary>
    /// 打字机效果显示文字
    /// </summary>
    /// <param name="text">文字内容</param>
    /// <param name="time">时间</param>
    /// <param name="action">结束后执行方法</param>
    void DoTweenText(string text, float time, UnityAction action)
    {
        Text tmpText = transform.GetComponent<Text>();
        tmpText.text = string.Empty;
        try
        {
            tmpText.DOText(text, time, true, ScrambleMode.None, null).SetEase(Ease.Linear).OnComplete(() => { action(); });
        }
        catch (System.NullReferenceException)
        {
            Debug.LogError("该对象不存在Text组件");
        }
    }
}

效果图:
在这里插入图片描述

2-2、实现Text的打字机效果

参考代码:

using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

/// <summary>
/// 用于Text的打字机效果组件。
/// </summary>
[RequireComponent(typeof(Text))]
public class TextWriter : MonoBehaviour
{
    /// <summary>
    /// 打字机效果状态。
    /// </summary>
    public enum TypewriterState
    {
        /// <summary>
        /// 已完成输出。
        /// </summary>
        Completed,

        /// <summary>
        /// 正在输出。
        /// </summary>
        Outputting,

        /// <summary>
        /// 输出被中断。
        /// </summary>
        Interrupted
    }
    /// <summary>
    /// 打字机效果用时
    /// </summary>
    private float useTime;

    /// <summary>
    /// 打字机效果状态。
    /// </summary>
    private TypewriterState state = TypewriterState.Completed;

    /// <summary>
    /// Text组件。
    /// </summary>
    private Text tmpText;

    /// <summary>
    /// 文本内容。
    /// </summary>
    string words;

    /// <summary>
    /// 显示间隔。
    /// </summary>
    int charsSecond;

    /// <summary>
    /// 用于输出字符的协程。
    /// </summary>
    private Coroutine outputCoroutine;

    /// <summary>
    /// 字符输出结束时的回调。
    /// </summary>
    private UnityAction outputEndCallback;


    void Awake()
    {
        tmpText = GetComponent<Text>();
    }

    private void Start()
    {
        OutputText("123456", 12, () => {

            Debug.Log("用12秒显示6个字");
        });
    }

    void OnDisable()
    {
        // 中断输出
        if (state == TypewriterState.Outputting)
        {
            state = TypewriterState.Interrupted;
            StopCoroutine(outputCoroutine);
            OnOutputEnd(true);
        }
    }

    /// <summary>
    /// 输出文字。
    /// </summary>
    /// <param name="text"></param>
    /// <param name="onOutputEnd"></param>
    public void OutputText(string text, float time, UnityAction onOutputEnd = null)
    {
        // 如果当前正在执行字符输出,将其中断
        if (state == TypewriterState.Outputting)
        {
            StopCoroutine(outputCoroutine);

            state = TypewriterState.Interrupted;
            OnOutputEnd(false);
        }

        tmpText.text = text;
        useTime = time;
        outputEndCallback = onOutputEnd;
        words = text;

        // 如果对象未激活,直接完成输出
        if (!isActiveAndEnabled)
        {
            state = TypewriterState.Completed;
            OnOutputEnd(true);
            return;
        }
        outputCoroutine = StartCoroutine(OutputText());
    }

    /// <summary>
    /// 以不带淡入效果输出字符的协程。
    /// </summary>
    /// <param name="skipFirstCharacter"></param>
    /// <returns></returns>
    private IEnumerator OutputText()
    {
        state = TypewriterState.Outputting;

        // 先隐藏所有字符
        tmpText.text = "";

        // 按时间逐个显示字符
        float timer = 0f;
        Text textInfo = tmpText;
        float speed = useTime / words.Length;//计算出出现文字的间隔
        while (charsSecond < words.Length)
        {
            timer += Time.deltaTime;
            if (timer >= speed)
            {
                timer = 0;
                charsSecond++;
                tmpText.text = words.Substring(0, charsSecond);
            }
            yield return null;
        }

        // 输出过程结束
        state = TypewriterState.Completed;
        OnOutputEnd(false);
    }

    /// <summary>
    /// 完成正在进行的打字机效果,将所有文字显示出来。
    /// </summary>
    public void CompleteOutput()
    {
        if (state == TypewriterState.Outputting)
        {
            state = TypewriterState.Completed;
            StopCoroutine(outputCoroutine);
            OnOutputEnd(true);
        }
    }

    /// <summary>
    /// 处理输出结束逻辑。
    /// </summary>
    /// <param name="isShowAllCharacters"></param>
    private void OnOutputEnd(bool isShowAllCharacters)
    {
        // 清理协程
        outputCoroutine = null;

        // 将所有字符显示出来
        if (isShowAllCharacters)
        {
            tmpText.text = words;
        }

        // 触发输出完成回调
        if (outputEndCallback != null)
        {
            var temp = outputEndCallback;
            outputEndCallback = null;
            temp.Invoke();
        }
    }
}

效果图:
在这里插入图片描述

2-3、使用TextMeshPro实现打字机效果

参考代码:

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

namespace Tools
{
    /// <summary>
    /// 打字机效果状态。
    /// </summary>
    public enum TypewriterState
    {
        /// <summary>
        /// 已完成输出。
        /// </summary>
        Completed,

        /// <summary>
        /// 正在输出。
        /// </summary>
        Outputting,

        /// <summary>
        /// 输出被中断。
        /// </summary>
        Interrupted
    }
    /// <summary>
    /// 用于TextMeshPro的打字机效果组件。
    /// </summary>
    [RequireComponent(typeof(TextMeshProUGUI))]
    public class TextWriterTmp : MonoBehaviour
    {
        /// <summary>
        /// 打字机效果用时
        /// </summary>
        private float useTime;

        /// <summary>
        /// 打字机效果状态。
        /// </summary>
        private TypewriterState state = TypewriterState.Completed;

        /// <summary>
        /// TextMeshPro组件。
        /// </summary>
        private TMP_Text tmpText;

        /// <summary>
        /// 用于输出字符的协程。
        /// </summary>
        private Coroutine outputCoroutine;

        /// <summary>
        /// 字符输出结束时的回调。
        /// </summary>
        private UnityAction outputEndCallback;

        /// <summary>
        /// 输出文字。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="onOutputEnd"></param>
        public void OutputText(string text, float time, UnityAction onOutputEnd = null)
        {
            // 如果当前正在执行字符输出,将其中断
            if (state == TypewriterState.Outputting)
            {
                StopCoroutine(outputCoroutine);

                state = TypewriterState.Interrupted;
                OnOutputEnd(false);
            }

            tmpText.text = text;
            useTime = time;
            outputEndCallback = onOutputEnd;

            // 如果对象未激活,直接完成输出
            if (!isActiveAndEnabled)
            {
                state = TypewriterState.Completed;
                OnOutputEnd(true);
                return;
            }
            outputCoroutine = StartCoroutine(OutputText());

        }

        /// <summary>
        /// 完成正在进行的打字机效果,将所有文字显示出来。
        /// </summary>
        public void CompleteOutput()
        {
            if (state == TypewriterState.Outputting)
            {
                state = TypewriterState.Completed;
                StopCoroutine(outputCoroutine);
                OnOutputEnd(true);
            }
        }

        private void Awake()
        {
            tmpText = GetComponent<TMP_Text>();
        }

        private void Start()
        {
            OutputText("123456", 6, () => 
            {
                Debug.Log("用6秒显示6个字");
            });
        }

        private void OnDisable()
        {
            // 中断输出
            if (state == TypewriterState.Outputting)
            {
                state = TypewriterState.Interrupted;
                StopCoroutine(outputCoroutine);
                OnOutputEnd(true);
            }
        }

        /// <summary>
        /// 以不带淡入效果输出字符的协程。
        /// </summary>
        /// <param name="skipFirstCharacter"></param>
        /// <returns></returns>
        private IEnumerator OutputText(bool skipFirstCharacter = false)
        {
            state = TypewriterState.Outputting;

            // 先隐藏所有字符
            tmpText.maxVisibleCharacters = skipFirstCharacter ? 1 : 0;
            tmpText.ForceMeshUpdate();

            // 按时间逐个显示字符
            float timer = 0f;
            TMP_TextInfo textInfo = tmpText.textInfo;
            float speed = useTime / textInfo.characterCount;
            while (tmpText.maxVisibleCharacters < textInfo.characterCount)
            {
                timer += Time.deltaTime;
                if (timer >= speed)
                {
                    timer = 0;
                    tmpText.maxVisibleCharacters++;
                }
                yield return null;
            }

            // 输出过程结束
            state = TypewriterState.Completed;
            OnOutputEnd(false);
        }



        /// <summary>
        /// 设置字符的顶点颜色Alpha值。
        /// </summary>
        /// <param name="index"></param>
        /// <param name="alpha"></param>
        private void SetCharacterAlpha(int index, byte alpha)
        {
            var materialIndex = tmpText.textInfo.characterInfo[index].materialReferenceIndex;
            var vertexColors = tmpText.textInfo.meshInfo[materialIndex].colors32;
            var vertexIndex = tmpText.textInfo.characterInfo[index].vertexIndex;

            vertexColors[vertexIndex + 0].a = alpha;
            vertexColors[vertexIndex + 1].a = alpha;
            vertexColors[vertexIndex + 2].a = alpha;
            vertexColors[vertexIndex + 3].a = alpha;
        }

        /// <summary>
        /// 处理输出结束逻辑。
        /// </summary>
        /// <param name="isShowAllCharacters"></param>
        private void OnOutputEnd(bool isShowAllCharacters)
        {
            // 清理协程
            outputCoroutine = null;

            // 将所有字符显示出来
            if (isShowAllCharacters)
            {
                var textInfo = tmpText.textInfo;
                for (int i = 0; i < textInfo.characterCount; i++)
                {
                    SetCharacterAlpha(i, 255);
                }

                tmpText.maxVisibleCharacters = textInfo.characterCount;
                tmpText.ForceMeshUpdate();
            }

            // 触发输出完成回调
            if (outputEndCallback != null)
            {
                var temp = outputEndCallback;
                outputEndCallback = null;
                temp.Invoke();
            }
        }
    }
}

效果图:
在这里插入图片描述

三、后记

如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。


你的点赞就是对博主的支持,有问题记得留言:

博主主页有联系方式。

博主还有跟多宝藏文章等待你的发掘哦:

专栏方向简介
Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。
Unity3D从入门到进阶入门从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。
Unity3D之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实战 | YOLOv10 自定义数据集训练实现车牌检测 (数据集+训练+预测 保姆级教程)

导读 本文主要介绍如何使用YOLOv10在自定义数据集训练实现车牌检测 (数据集训练预测 保姆级教程)。 YOLOv10简介 YOLOv10是清华大学研究人员在Ultralytics Python包的基础上&#xff0c;引入了一种新的实时目标检测方法&#xff0c;解决了YOLO以前版本在后处理和模型架构方面…

挂上了代理加速器梯子之后,Git clone指令下载仍旧很慢的问题

当你使用了各种代理软件访问诸如Github、Google、油管、推特这些网址&#xff0c;你会发现基本可以访问&#xff0c;只不过是访问速度不同&#xff0c;但是不管你使用什么代理软件&#xff0c;你的git clone指令从Github远程库下载库的速度都不会受到影响。 当使用代理软件访问…

LIP模型动力学方程例子

线性倒立摆(Linear Inverted Pendulum, LIP)模型是用于描述和控制人形机器人步态的重要工具。LIP模型假设质心沿着一条固定的直线运动,并且所有质量集中在质心上。这简化了计算,使得模型更容易用于控制和稳定分析。 LIP模型动力学方程 LIP模型的基本假设是: 机器人的质心…

【原创】海为PLC与RS-WS-ETH-6传感器的MUDBUS_TCP通讯

点击“蓝字”关注我们吧 一、关于RS-WS-ETH-6传感器的准备工作 要完成MODBUS_TCP通讯,我们必须要知道设备的IP地址如何分配,只有PLC和设备的IP在同一网段上,才能建立通讯。然后还要选择TCP的工作模式,来建立设备端和PC端的端口号。接下来了解设备的报文格式,方便之后发送…

如何有效释放Docker占用的存储空间

随着Docker的广泛应用&#xff0c;我们经常会遇到Docker占用过多存储空间的问题。这可能是由于频繁的镜像拉取、容器创建和删除等操作导致的。本文将介绍几种方法来有效释放Docker占用的存储空间&#xff0c;特别是docker system prune命令的使用。 Docker的存储机制 Docker使…

浔川python社官方警告——浔川总社部、浔川社团举报中心

昨天&#xff0c;浔川社团举报中心接到举报&#xff0c;说有被侵权文章。 今天&#xff0c;小编再搜索“怎么加入浔川python社”时 &#xff0c;看到了假冒浔川python社的网站。 该网站我社团并不认识&#xff0c;并且侵权了我社 《用python做的一个登录界面——浔川python社》…

海思SS928(SD3403)部署YOLOv5-YOLOv7步骤详解

1. YOLO模型资料 本文档内容以yolov5-7.0工程、yolov5s模型为例。 a. 模型结构 详细的模型结构可以利用netron工具打开.pt或.onnx模型查看。 b. 模型参数即验证结果 其中,YOLOv5n、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x为五种类型的预训练模型,其包含的检测类别相…

vue element 接口返回数据与控制台打印数据不一致 踩坑

问题描述&#xff1a; 接口返回数据正常&#xff0c;&#xff0c;控制台打印不对&#xff0c;element el-switch表格中使用&#xff0c;控制台打印数据被改变 如下正常数据 数据id 17状态是0 控制台打印状态却是1 造成原因&#xff1a; element el-seitch组件修改了状态 修…

【Vue】声明式导航-导航链接

文章目录 一、引入二、解决方案三、代码示例四、声明式导航-两个类名1&#xff09;router-link-active2&#xff09;router-link-exact-active 一、引入 但凡说到声明式导航&#xff0c;都需要想到router-link 需求 实现导航高亮效果 如果使用a标签进行跳转的话&#xff0c;需要…

TensorFlow2.x基础与mnist手写数字识别示例

文章目录 Github官网文档Playground安装声明张量常量变量 张量计算张量数据类型转换张量数据维度转换ReLU 函数Softmax 函数卷积神经网络训练模型测试模型数据集保存目录显示每层网络的结果 TensorFlow 是一个开源的深度学习框架&#xff0c;由 Google Brain 团队开发和维护。它…

【学术小白成长之路】01三方演化博弈(基于复制动态方程) -基础概念与模型构建

1.演化博弈基础知识 经典博弈论起源于1944年Von Neumann和Morgenstern合著的《博弈论与经济学行为》&#xff0c;是研究理性决策者之间竞争和合作关系的数学方法。 博弈论主要研究完全理性的博弈个体为实现利益最大化而做的策略选择&#xff0c;在过去几十年取得了极大发展&am…

Camtasia Studio怎么自动加字幕呢,Camtasia Studio有什么功能呢

在信息化高度发达的今天&#xff0c;视频作为一种直观、生动的信息表达方式&#xff0c;受到了越来越多人的青睐。无论是教育领域的教学视频&#xff0c;还是企业宣传的推广短片&#xff0c;甚至是个人创作的分享作品&#xff0c;都离不开一款优秀的视频编辑软件。Camtasia Stu…

番外篇 | 利用华为2023最新Gold-YOLO中的Gatherand-Distribute对特征融合模块进行改进

前言:Hello大家好,我是小哥谈。论文提出一种改进的信息融合机制Gather-and-Distribute (GD) ,通过全局融合多层特征并将全局信息注入高层,以提高YOLO系列模型的信息融合能力和检测性能。通过引入MAE-style预训练方法,进一步提高模型的准确性。🌈 目录 🚀1.论文解…

全志D1s软件入门之Tina Linux烧写教程

烧写 Tina Linux 烧写&#xff0c;即将编译打包好的固件下载到设备 烧写方式简介 全志平台为开发者提供了多种多样的烧写方式和烧写工具&#xff1a; &#xff08;1&#xff09; PhoenixSuit&#xff1a;基于Windows的系统的烧写工具&#xff0c;是最常用的烧写工具&#x…

【三十三】springboot+序列化实现返回值脱敏和返回值字符串时间格式化问题

互相交流入口地址 整体目录&#xff1a; 【一】springboot整合swagger 【二】springboot整合自定义swagger 【三】springboot整合token 【四】springboot整合mybatis-plus 【五】springboot整合mybatis-plus 【六】springboot整合redis 【七】springboot整合AOP实现日志操作 【…

解决VIvado编程中遇到的bug 5

解决VIvado编程中遇到的bug 5 语言 &#xff1a;Verilg HDL EDA工具&#xff1a; Vivado、quartus2 、modelsim 解决VIvado编程中遇到的bug 5一、引言二、问题、分析及解决方法1. vivado编译时报错&#xff08;1&#xff09;错误&#xff08;2&#xff09;分析&#xff08;3&am…

【C++课程学习】:C++入门(引用)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 &#x1f369;1.引用的概念&#xff1a; &#x1f369;2.引用和指针是两个概念&#xff1a; &#x…

C语言之字符函数总结(全部!),一篇记住所有的字符函数

前言 还在担心关于字符的库函数记不住吗&#xff1f;不用担心&#xff0c;这篇文章将为你全面整理所有的字符函数的用法。不用记忆&#xff0c;一次看完&#xff0c;随查随用。用多了自然就记住了 字符分类函数和字符转换函数 C语言中有一系列的函数是专门做字符分类和字符转换…

【AI基础】第三步:纯天然保姆喂饭级-安装并运行chatglm2-6b

chatglm2构建时使用了RUST&#xff0c;所以在安装chatglm2之前&#xff0c;先安装RUST。 此系列文章列表&#xff1a; 【AI基础】第一步&#xff1a;安装python开发环境-windows篇_下载安装ai环境python-CSDN博客 【AI基础】第一步&#xff1a;安装python开发环境-conda篇_mini…

springboot+minio+kkfileview实现文件的在线预览

在原来的文章中已经讲述过springbootminio的开发过程&#xff0c;这里不做讲述。 原文章地址&#xff1a; https://blog.csdn.net/qq_39990869/article/details/131598884?spm1001.2014.3001.5501 如果你的项目只是需要在线预览图片或者视频那么可以使用minio自己的预览地址进…