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

推荐阅读

  • 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.mfbz.cn/a/691086.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】进程4——进程状态

1.进程状态 什么是状态&#xff1f; 每个人都有状态——颓废&#xff0c;阳光&#xff0c;积极向上。。。。 进程也有状态 在操作系统中&#xff0c;由于进程的数量是非常多的&#xff0c;而系统的资源又非常少&#xff0c;所以不可能每一个进程在每时每刻都会处于上处理机运…

Python语言读取图像

import cv2 import numpy as np width 640 # 图像宽度height 480 # 图像高度channels 3 # 颜色通道数imgEmpty np.empty((height, width, channels), np.uint8) # 创建空白数组imgBlack np.zeros((height, width, channels), np.uint8) # 创建黑色图像 RGB0imgWhite …

微型丝杆与滚珠丝杆性能差异与适用场景!

滚珠丝杆是工具机械和精密机械上最常使用的传动元件&#xff0c;其主要功能是将旋转运动转换成线性运动&#xff0c;或将扭矩转换成轴向反复作用力。同时兼具高精度、可逆性和高效率的特点。而微型丝杆是一种直径为0.5mm以下且线性误差在几微米以内&#xff0c;精度高、传动稳定…

开发uniapp 小程序时遇到的问题

1、【微信开发者工具报错】routeDone with a webviewId XXX that is not the current page 解决方案: 在app.json 中添加 “lazyCodeLoading”: “requiredComponents” uniapp的话加到manifest.json下的mp-weixin 外部链接文章&#xff1a;解决方案文章1 解决方案文章2 &qu…

LLM的基础模型2:Transformer的组成模块

Transformer是一种先进的语言模型&#xff0c;它在预测下一个单词或标记方面与传统的语言模型有所不同&#xff0c;但仍然遵循相同的基本原理。Transformer通过一系列复杂的步骤&#xff0c;将输入的标记序列转换为能够进行预测的丰富向量序列。 在Transformer中&#xff0c;输…

反转链表 (oj题)

一、题目链接 https://leetcode.cn/problems/reverse-linked-list/submissions/538124207 二、题目思路 1.定义三个指针&#xff0c;p1先指向NULL p2指向头结点 p3指向第二个结点 2.p2的next指向p1。然后移动指针&#xff0c;p1来到p2的位置&#xff0c;p2来到p3的位置&…

二开版微交易系统

下载地址&#xff1a;二开版微交易系统

验证码案例

目录 前言 一、Hutool工具介绍 1.1 Maven 1.2 介绍 1.3 实现类 二、验证码案例 2.1 需求 2.2 约定前后端交互接口 2.2.1 需求分析 2.2.2 接口定义 2.3 后端生成验证码 2.4 前端接收验证码图片 2.5 后端校验验证码 2.6 前端校验验证码 2.7 后端完整代码 前言…

vue项目搭建

目录 引入依赖1. elementa. notifyb. el-dropdown-item绑定点击事件点击无效c. 页面重新加载d. 路由新页面打开e.Scrollbar 滚动条 2. main.js模板3.axios post请求参数4. 数据保存在本地5. mavon-editor6. 获得路由参数7.远程搜索8.参数传入自定义参数9.固定屏幕不动10.有时事…

Elasticsearch 认证模拟题 - 14

一、题目 在集群中输入以下指令&#xff1a; PUT phones/_doc/1 {"brand":"Samsumg","model":"Galaxy S9","features":[{"type":"os", "value":"Android"},{"type":&q…

Edge怎么关闭快捷键

Edge怎么关闭快捷键 在Edge浏览器中&#xff0c;你可以通过以下步骤关闭快捷键&#xff1a; 打开Edge浏览器&#xff0c;输入&#xff1a;edge://flags 并按下回车键。 在Flags页面中&#xff0c;搜索“快捷键”(Keyboard shortcuts)选项。 将“快捷键”选项的状态设置为“…

【SpringBoot】项目搭建基本步骤(整合 Mybatis)

搭建 SpringBoot 项目有两种方式&#xff1a;使用 IDEA、或者在 Spring 官网下载。 1. IDEA 创建 打开 IDEA 后&#xff0c;英文版请点击 File -> New -> Project -> Spring Initialer。 中文版请点击 文件 -> 新建 -> 项目 -> Spring Initialer。 在打开的…

老师如何制作高考后志愿填报信息采集系统?

高考结束后&#xff0c;志愿填报成为学生们的头等大事。面对众多选择&#xff0c;如何高效、准确地填报志愿&#xff0c;是每个学生和家长都关心的问题。作为老师&#xff0c;能否利用现有的技术工具&#xff0c;帮助学生更好地完成志愿填报呢&#xff1f; 老师们需要一个能够…

机器学习作业6——svm支持向量机

目录 一、理论 概念&#xff1a; 线性可分&#xff1a; 支持向量&#xff1a; 间隔&#xff1a; 目标&#xff1a; 软间隔&#xff1a; 梯度下降法&#xff1a; 别的方法&#xff1a; 拉格朗日函数&#xff1a; SMO算法&#xff1a; 核函数&#xff1a; 二、代码 …

Zemax中FFT PSF和惠更斯PSF的区别?

在Zemax“分析”选项卡中&#xff0c;有PSF&#xff08;“点扩散函数”&#xff09;图&#xff0c;主要包括如下两种计算方式&#xff1a; 1. FFT PSF&#xff0c;快速傅里叶变换&#xff08;fast fourier transform&#xff0c;FFT&#xff09; 该方法可以看做是以下点扩散函…

【录制,纯正人声】OBS录制软件,音频电流音,杂音解决办法,录制有噪声的解决办法

速度解决的方法 &#xff08;1&#xff09;用RNNoise去除噪声。RNNoise是一个开源的&#xff0c;效果不好的噪声去除器。使用方法就是点击滤镜&#xff0c;然后加噪声抑制RNNoise。【这方法不好用】 &#xff08;2&#xff09;用Krisp(https://krisp.ai/) 去除噪声。这个Kris…

华为云服务器-云容器引擎 CCE环境构建及项目部署

1、切换地区 2、搜索云容器引擎 CCE 3、购买集群 4、创建容器节点 通过漫长的等待(五分钟左右)&#xff0c;由创建中变为运行中&#xff0c;则表明容器已经搭建成功 购买成功后&#xff0c;返回容器控制台界面 5、节点容器管理 6、创建redis工作负载 7、创建mysql工作负载 8、…

有效的括号(oj题)

一、题目链接 https://leetcode.cn/problems/valid-parentheses/submissions/538110206 二、题目思路 利用栈的性质&#xff0c;后进先出 1.依次读取字符串&#xff0c;判断是否为左括号&#xff0c;如果是&#xff0c;就将其入栈。 2.如果读取的不是左括号&#xff0c;就说…

c++编译器在什么情况下会提供类的默认构造函数等,与析构函数

我们都知道&#xff0c;在 c 里&#xff0c;编写的简单类&#xff0c;若没有自己编写构造析构函数与 copy 构造函数 与 赋值运算符函数&#xff0c;那么编译器会提供这些函数&#xff0c;并实现简单的语义&#xff0c;比如成员赋值。看 源码时&#xff0c;出现了下图类似的情形…

如何使用Python的Turtle模块绘制小猪

一、前置条件 在开始学习如何使用Python的Turtle模块进行绘画之前&#xff0c;请确保你的电脑已安装Python环境。如果尚未安装Python&#xff0c;你可以从Python官网下载并安装最新版本。 Turtle模块是Python内置的一个用于绘图的库&#xff0c;通常不需要额外安装。如果你发…