Unity 实现字幕打字效果

Text文本打字效果,TextMeshPro可以对应参考,差距不大,改改参数名就能用。改脚本原本被我集成到其他的程序集中,现在已经分离。

效果

请添加图片描述

实现功能

1.能够设置每行能够容纳的字数和允许的冗余
2.打字效果
3.每行打完上移
4.开头进入,结束弹出
5.行居中

脚本使用

请添加图片描述
请添加图片描述

属性解释
TypingSpeed打字速度(.s 每过多少时间打一个)
RowShowMax一行显示的最大值
AllowRedundancy每行能够允许的冗余
IsUpdateText更新文本,默认不启动,勾选点击运行就更新
Text挂载text文本
OffsetY对每行上移的补偿
SaveMarqueeoriginPosition保存字幕整体的初始位置
TextCloseDelayTime字幕消失的时间(Obsolete)
BottomShow需要挂载下方显示的整体
函数功能
UpdateText更新文本,需要再Update中调用
OnFinish更新完成,更新文本完成后调用的函数
OnTextUpdate(string)文本更新,在打字过程中如果发生文本更新需要调用的方法
OnTextReset文本重置


设置

** 1.物体设置 **
请添加图片描述

** 2.text文本设置 **
请添加图片描述
1.需要文字的size(如果有外描边的话)来计算字占据的行宽,来决定每行上移的距离
2.文本每行居中,但定格显示

代码

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

namespace YBZ {

    public class TypewriterEffect : MonoBehaviour 
    {
     
        // 测试文本
        private readonly string text_test = "SVN中我需要维护的东西Scene; Scripts/Engine/WSC SteamingAsset/2DPivots.json Editor/WSCPivotEditor.cs \n 下方提示";

        [Header("文本显示"), Space(10)]
        public float typingSpeed = 0.2f; // 打字速度
        public int rowShowMax = 25; // 一行最大显示数量
        public int allowRedundancy = 6; // 允许的冗余数量
        public bool isUpdateText = false; // 是否播放

        public Text text; // 底部字幕

        [Range(-25, 25), Space(5)]
        public int offsetY = -3; // 第一行Y轴补偿
        public Vector3 saveMarqueeOriginPostion = new Vector3(0, -63, 0); // 下方字幕的原初位置

        private float textTimeCount = 0; // 更新用的计时器
        private string word = ""; //保存字幕
        private int currentPos = 0; // 打字字符索引
        private int LineBreakCount = 0; // 换行符计数

        private Vector3 saveTextLocatePostion;  // 用于保存TextUI位置

        private bool isOriginPosition = true;

        void Update() {
            UpdateText();
            if (Input.GetMouseButtonDown(0)) {
                OnTextUpdate(text_test);
            }
        }
        
        // 文本更新
        private void UpdateText() {
            if (!isUpdateText) {
                return;
            }

            // 检查字幕是否位于原初位置
            if (isOriginPosition) {
                isOriginPosition = !isOriginPosition;
                BottomShow.transform.DOLocalMove(Vector3.zero, 1.0f);
            }

            BottomShow.SetActive(true);

            if (saveTextLocatePostion == Vector3.zero) {
                saveTextLocatePostion = text.rectTransform.localPosition;
            }

            if (word == "") {
                word = text.text;
            }

            textTimeCount += Time.deltaTime;
            if (textTimeCount > typingSpeed) {
                textTimeCount = 0;
                currentPos++;
                if (currentPos >= word.Length) {
                    Debug.Log("播放完成");

                    OnFinish();
                    return;
                }
                text.text = word[..currentPos];//刷新文本显示内容
                if (word[currentPos - 1] == '\n') {
                    Debug.Log("发现换行符");
                    LineBreakCount++;

                    // 每次遇到一个换行符就上移25个单位
                    if (LineBreakCount == 1) {
                        text.rectTransform.DOLocalMoveY(text.rectTransform.localPosition.y + 25 + offsetY, 1f);
                    } else if (LineBreakCount != 1) {
                        text.rectTransform.DOLocalMoveY(text.rectTransform.localPosition.y + 25, 1f);
                    }

                }

                // 每次处理行超限
                int lineCount;
                if (LineBreakCount == 0) {
                    lineCount = text.text.Length;
                } else {
                    lineCount = text.text[text.text.LastIndexOf('\n')..].Length;
                }

                // 行超限
                if (lineCount > rowShowMax + allowRedundancy) {
                    word = text.text + '\n' + word[text.text.Length..];
                }

            }
        }

        [Header("下方显示延迟消失的所需要的时间")]
        public float textCloseDelayTime = 2.0f;

        /// <summary>
        /// 下方提示游戏物体,在使用前预加载
        /// </summary>
        public GameObject BottomShow;

        public IEnumerator IE_TextCloseDelayTime(float time) {
            yield return new WaitForSeconds(time);
            BottomShow.SetActive(false);
            Debug.Log("下方显示已关闭");
        }

        public IEnumerator IE_OnTextReset(float time) {
            yield return new WaitForSeconds(time);
            OnTextReset();
            Debug.Log("文本恢复默认");
            isOriginPosition = true;
            BottomShow.transform.DOLocalMove(saveMarqueeOriginPostion, 1.0f);
        }

        // 文本更新完成 , 一旦确认关闭就不要再更新文本, 否侧会出现逻辑错误,如若在播放完毕后更新文本一定要在下方显示关闭后, 字幕回滚的时候不能更新文本.
        private void OnFinish() {
            isUpdateText = false;
            // 完成之后下方显示 延迟关闭, 位置回调
            // StartCoroutine(IE_TextCloseDelayTime(textCloseDelayTime));
            // 延迟文本重置位置
            StartCoroutine(IE_OnTextReset(textCloseDelayTime));
            text.rectTransform.DOLocalMove(saveTextLocatePostion + new Vector3(0, offsetY, 0), textCloseDelayTime);
        }

        // 文本更新, 一旦更新就是确定要开始播放(╯‵□′)╯︵┻━┻(你更新不是为了播放?)
        private void OnTextUpdate(string newtext) {

            text ??= GameObject.Find("字幕文字").gameObject.GetComponent<Text>();
            OnTextReset();
            word = newtext;
            // StartCoroutine(IE_OnTextReset(0.5f));
            BottomShow.SetActive(true);
            isUpdateText = true;
        }

        // 文本恢復默认: 索引为0, 换行符统计为0, LocalPostion恢复, 文本置空
        private void OnTextReset() {
            if (saveTextLocatePostion == Vector3.zero) {
                saveTextLocatePostion = text.rectTransform.localPosition;
            }
            text.rectTransform.localPosition = saveTextLocatePostion;
            text.text = "";
            LineBreakCount = 0;
            currentPos = 0;
        }

        // 初始化
        public void Init() {
            Debug.Log("文本更新初始化完成");
        }

        public void UnInit() {
            Debug.Log("文本控制结束");
        }
        private void OnDestroy() {
            UnInit();
        }
    }
}

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

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

相关文章

Markdown系列之Flowchat流程图

一.欢迎来到我的酒馆 介绍Markdown的Flowchart流程图语法。 目录 一.欢迎来到我的酒馆二.什么是Flowchart三.更进一步 二.什么是Flowchart 2.1 Flowchart是一款基于javascript的工具&#xff0c;使用它可以用代码创建简单的流程图。具体信息可以查看flowchart官网&#xff1a;…

栈和队列的实现

Lei宝啊&#xff1a;个人主页&#xff08;也许有你想看的&#xff09; 愿所有美好不期而遇 前言 &#xff1a; 栈和队列的实现与链表的实现很相似&#xff0c;新瓶装旧酒&#xff0c;没什么新东西。 可以参考这篇文章&#xff1a; -------------------------无头单向不循环…

微信小程序开发【从0到1~入门篇】2023.08

一个小程序主体部分由三个文件组成&#xff0c;必须放在项目的根目录&#xff0c;如下&#xff1a; 文件必须作用app.js是小程序逻辑app.json是小程序公告配置app.wxss否小程序公告样式表 3. 小程序项目结构 一个小程序页面由四个文件组成&#xff0c;分别是&#xff1a; 文…

并查集维护额外信息,算法思路类似前缀和,结构类似扑克接龙

一、链接 240. 食物链 二、题目 动物王国中有三类动物 A,B,CA,B,C&#xff0c;这三类动物的食物链构成了有趣的环形。 AA 吃 BB&#xff0c;BB 吃 CC&#xff0c;CC 吃 AA。 现有 NN 个动物&#xff0c;以 1∼N1∼N 编号。 每个动物都是 A,B,CA,B,C 中的一种&#xff0c;…

Nginx使用proxy_cache指令设置反向代理缓存静态资源

场景 CentOS7中解压tar包的方式安装Nginx&#xff1a; CentOS7中解压tar包的方式安装Nginx_centos7 tar文件 怎么load_霸道流氓气质的博客-CSDN博客 参考上面流程实现搭建Nginx的基础上&#xff0c;实现静态资源的缓存设置。 注意上面安装时的目录是在/opt/nginx目录下&…

数组的学习

数组学习 文章目录 数组来由数组的使用数组的内存图变量声明和args参数说明声明分配空间值的省略写法数组的length属性数列输出求和判断购物金额结算Arrays的sort和toString方法Arrays的equals和fill和copyOf和binarySearch方法字符数组顺序和逆序输出 数组来由 录入30个学生…

Linux(进程)

Linux&#xff08;进程&#xff09; 1. 冯诺依曼结构体系2 . 操作系统&#xff08;OS&#xff09;3.进程task_ struct内容分类查看进程查看PID以及PPIDfork()Linux操作系统进程的状态僵尸进程孤儿进程进程优先级其他概念 1. 冯诺依曼结构体系 冯诺依曼结构也称普林斯顿结构&am…

FastAPI 构建 API 高性能的 web 框架(一)

如果要部署一些大模型一般langchainfastapi&#xff0c;或者fastchat&#xff0c; 先大概了解一下fastapi,本篇主要就是贴几个实际例子。 官方文档地址&#xff1a; https://fastapi.tiangolo.com/zh/ 1 案例1:复旦MOSS大模型fastapi接口服务 来源&#xff1a;大语言模型工程…

云计算——ACA学习 云计算概述

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 写在前面 上章回顾 本章简介 本章目标 一.云计算产生背景 1.信息时代的重点变革…

shell中的函数

整理思维导图 写一个函数&#xff0c;获取用户的uid和gid并使用变量接收 #!/bin/bashfunction get() {userwhoamiuidid -u $usergidid -g $userecho "该用户的uid为$uid"echo "该用户的gid为$gid"} get整理冒泡排序、选择排序和快速排序的代码 冒泡排序 #…

【Hystrix技术指南】(1)基本使用和配置说明

这世间许多事物皆因相信而存在&#xff0c;所以人们亲手捏出了泥菩萨&#xff0c;却选择坚定的去信仰它。 分布式系统的规模和复杂度不断增加&#xff0c;随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中&#xff0c;【熔断、隔离、降级、限流】是经常被…

阿里云平台注册及基础使用

首先进入阿里云官网&#xff1a; 阿里云-计算&#xff0c;为了无法计算的价值 点击右上角“登录/注册”&#xff0c;如果没有阿里云账号则需要注册。 注册界面&#xff1a; 注册完成后需要开通物联网平台公共实例&#xff1a; 注册成功后的登录&#xff1a; 同样点击右上角的…

Self-Attention、transformer代码、word2vec理论(skip-gram、CNOW)、近似训练 (第十三次组会)

@[TOC](Self-Attention、transformer代码、word2vec理论(skip-gram、CNOW)、近似训练 (第十三次组会)) Self-Attention相关 Transformer代码

vue2 todoapp案例(静态)

1.创建三个子组件(TodoHeader、TodoMain、TodoFooter)和两个(index.css、base.css)样式&#xff1b; TodoHeader页面 <template><header class"header"><h1>todos</h1><input id"toggle-all" class"toggle-all" typ…

使用gpt对对话数据进行扩增,对话数据扩增,数据增强

我们知道一个问题可以使用很多方式问&#xff0c;但都可以使用完全一样的回答&#xff0c;基于这个思路&#xff0c;我们可以很快的扩增我们的数据集。思路就是使用chatgpt或者gpt4生成类似问题&#xff0c;如下&#xff1a; 然后我们可以工程化这个过程&#xff0c;从而快速扩…

IP核之fifo

一.FIFO简介 FIFO (First In First Out&#xff0c;即先入先出&#xff09;&#xff0c;是一种数据缓冲器&#xff0c;用来实现数据先入先出的读写方式。 二&#xff0c;FIFO实现原理 FIFO是采用一种先入先出的实现原理 就如图按照D1到D10的顺序输入那么读取的时候也是按照D…

Python(七十二)集合的相关操作(增删改查)

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版是一个完整的软件音乐制作环境或数字音频工作站&#xff08;DAW&#xff09;。它代表了 25 多年的创新发展&#xff0c;将您创作、编曲、录…

Framework才是Android 开发的热门技术~

相信大家都有感觉到今年的市场竞争的激烈&#xff0c;投出简历并不像往年一样立马就有回应&#xff0c;大多是这种情况&#xff1a;投出简历没有停歇&#xff0c;状态却是70%未读&#xff0c;30%已读。 这种情况并不是说市场落寞了&#xff0c;不招人了&#xff0c;而是经过了…

【Datawhale AI 夏令营第二期】AI 量化模型预测挑战赛

文章目录 赛题分析赛题背景赛事任务赛题数据集评价指标 Baseline实践导入模块EDA特征工程模型训练与验证结果输出 改进 赛题分析 赛题背景 量化金融在国外已经有数十年的历程&#xff0c;而在国内兴起还不到十年。这是一个极具挑战的领域。量化金融结合了数理统计、金融理论、…