Unity TMP文字移动效果

news2024/12/26 15:14:18

前言

看见很多游戏有很特殊的波浪形文字效果,于是来尝试一下控制TMP文字顶点的方式达到类似效果。

原理

挂载tmp text,在里面随便放入非空格字符。

tmp text组件开放了textInfo接口,也就是GetComponent<TextMeshProUGUI>().textInfo可以获取text字符串信息:

 characterInfo[i].vertexIndex用于找到这个字符起始index;meshInfo[TMP_CharacterInfo.materialReferenceIndex]用于获取mesh信息,再进一层meshInfo.vertices即可拿到顶点信息。

我们就是强行修改vertices信息,然后调用TextMeshProUGUI.UpdateVertexData()即可完成text不同字符间的修改。

保存原始字符顶点vertices信息

//tmp组件
TextMeshProUGUI m_txtSelf = null;
//移动周期
float m_moveTotalTime = 1f;
//上下浮动幅度
float m_amplitude = 100;
Vector3[] m_rawVertex;

public void Awake()
{
    m_txtSelf = transform.GetComponent<TextMeshProUGUI>();
}

private void GetRawVertex()
{
    m_txtSelf.ForceMeshUpdate();
    if (m_txtSelf.textInfo.characterCount > 0)
    {
        TMP_CharacterInfo charInfo = m_txtSelf.textInfo.characterInfo[0];
        TMP_MeshInfo meshInfo = m_txtSelf.textInfo.meshInfo[charInfo.materialReferenceIndex];
        //创建对象来保存初始值
        m_rawVertex = new Vector3[meshInfo.vertices.Length];
        for (int i = 0; i < meshInfo.vertices.Length; i++)
        {
            m_rawVertex[i] = new Vector3(meshInfo.vertices[i].x, meshInfo.vertices[i].y, meshInfo.vertices[i].z);
        }
    }
}

public void Start()
{
    GetRawVertex();
}

所有字符一起移动

用协程每隔一段时间做一次循环运动,用dotween.to附加lamda表达式来完成字符串移动:

public void Start()
{
    GetRawVertex();
    StartCoroutine(Shake());
}
public IEnumerator Shake()
{
    while(true)
    {
        Tweener tweener = DOTween.To(() => 0f, y =>
        {
            for (int i = 0; i < m_txtSelf.textInfo.characterCount; i++)
            {
                // 获取字符信息和MeshInfo
                TMP_CharacterInfo currentCharInfo = m_txtSelf.textInfo.characterInfo[i];
                TMP_MeshInfo meshInfo = m_txtSelf.textInfo.meshInfo[currentCharInfo.materialReferenceIndex];

                int nextVertexIndex = meshInfo.vertices.Length;
                if (i < m_txtSelf.textInfo.characterCount - 1)
                {
                    TMP_CharacterInfo nextCharInfo = m_txtSelf.textInfo.characterInfo[i + 1];
                    nextVertexIndex = nextCharInfo.vertexIndex;
                }

                // 获取起始顶点索引
                int vertexIndex = currentCharInfo.vertexIndex;

                // 顶点偏移
                for (int j = vertexIndex; j < nextVertexIndex; j++)
                {
                    float yOffset = y;
                    if (yOffset >= 0 && yOffset <= 1)
                    {
                        meshInfo.vertices[j] = m_rawVertex[j] + Mathf.Sin(yOffset * Mathf.PI) * Vector3.up * m_amplitude;
                    }
                }
            }
            m_txtSelf.UpdateVertexData();
        }, 2, m_moveTotalTime);

        yield return new WaitForSeconds(m_moveTotalTime);
    }
}

 效果如下显示:

 每个字符规律跳动

就需要在y->yOffset中加入位置参数变量,用以形成类波浪效果:

float yOffset = y - (float)i / m_txtSelf.textInfo.characterCount;

 至此即可完成。

全部代码

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

public class test : MonoBehaviour
{
    //tmp组件
    TextMeshProUGUI m_txtSelf = null;
    //移动周期
    float m_moveTotalTime = 1f;
    //上下浮动幅度
    float m_amplitude = 100;
    Vector3[] m_rawVertex;

    public void Awake()
    {
        m_txtSelf = transform.GetComponent<TextMeshProUGUI>();
    }

    private void GetRawVertex()
    {
        m_txtSelf.ForceMeshUpdate();
        if (m_txtSelf.textInfo.characterCount > 0)
        {
            TMP_CharacterInfo charInfo = m_txtSelf.textInfo.characterInfo[0];
            TMP_MeshInfo meshInfo = m_txtSelf.textInfo.meshInfo[charInfo.materialReferenceIndex];
            //创建对象来保存初始值
            m_rawVertex = new Vector3[meshInfo.vertices.Length];
            for (int i = 0; i < meshInfo.vertices.Length; i++)
            {
                m_rawVertex[i] = new Vector3(meshInfo.vertices[i].x, meshInfo.vertices[i].y, meshInfo.vertices[i].z);
            }
        }
    }

    public void Start()
    {
        GetRawVertex();
        StartCoroutine(Shake());
    }
    public IEnumerator Shake()
    {
        yield return new WaitForSeconds(1);
        while (true)
        {
            Tweener tweener = DOTween.To(() => 0f, y =>
            {
                for (int i = 0; i < m_txtSelf.textInfo.characterCount; i++)
                {
                    // 获取字符信息和MeshInfo
                    TMP_CharacterInfo currentCharInfo = m_txtSelf.textInfo.characterInfo[i];
                    TMP_MeshInfo meshInfo = m_txtSelf.textInfo.meshInfo[currentCharInfo.materialReferenceIndex];

                    int nextVertexIndex = meshInfo.vertices.Length;
                    if (i < m_txtSelf.textInfo.characterCount - 1)
                    {
                        TMP_CharacterInfo nextCharInfo = m_txtSelf.textInfo.characterInfo[i + 1];
                        nextVertexIndex = nextCharInfo.vertexIndex;
                    }

                    // 获取起始顶点索引
                    int vertexIndex = currentCharInfo.vertexIndex;

                    // 顶点偏移
                    for (int j = vertexIndex; j < nextVertexIndex; j++)
                    {
                        float yOffset = y - (float)i / m_txtSelf.textInfo.characterCount;
                        if (yOffset >= 0 && yOffset <= 1)
                        {
                            meshInfo.vertices[j] = m_rawVertex[j] + Mathf.Sin(yOffset * Mathf.PI) * Vector3.up * m_amplitude;
                        }
                    }
                }
                m_txtSelf.UpdateVertexData();
            }, 2, m_moveTotalTime);

            yield return new WaitForSeconds(m_moveTotalTime);
        }
    }
}

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

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

相关文章

使用R语言进行Logistic回归分析(2)

一、数据集描述&#xff0c;问题要求 下表是40位肺癌病人的生存资料&#xff0c;X1表示生活行为能力平分&#xff08;1到100&#xff09;&#xff0c;X2为病人的年龄&#xff08;年&#xff09;&#xff0c;X3由诊断到进入研究的时间&#xff08;月&#xff09;&#xff0c;X4…

VMwareWorkstation17.0虚拟机搭建WindowsXP虚拟机(完整安装步骤详细图文教程)

VMwareWorkstation17.0虚拟机搭建WindowsXP虚拟机&#xff08;完整安装步骤详细图文教程&#xff09; 一、Windows XP1.Windows XP简介2.Windows XP 的下载地址 二、配置 Windows XP 虚拟机运行环境1.新建虚拟机2.选择类型配置3.插入WinXP光盘映像文件(ISO)4.选择操作系统5.命名…

【MCAL】TC397+EB-tresos之CAN配置实战 - (CAN/CANFD)

本篇文章介绍了在TC397平台使用EB-tresos对CAN驱动模块进行配置的实战过程,不仅介绍了标准CAN的发送与接收&#xff0c;还介绍了CANFD的实现与调试以及扩展帧的使用。M_CAN是德国博世公司开发的IP&#xff0c;因为英飞凌的芯片完整的集成了这个IP&#xff0c;所以整体的配置都比…

【电路笔记】-RC网络-时间常数

时间常数 文章目录 时间常数1、概述2、RC 电路的时间常数3、示例14、示例25、RC瞬态放电曲线6、示例37、总结Tau τ \tau τ 是 RC 电路在阶跃变化输入条件下从一种稳态条件变为另一种稳态条件所需的时间常数。 1、概述 Tau,符号 τ \tau τ,是电气和电子计算中使用的希腊字…

C++_数据结构_数据的输入

作用 用于从键盘获取数据 关键字 cin >> 变量示例

Jenkins的Pipeline概念

文章目录 Pipeline什么是Jenkins Pipeline声明式和脚本式Pipeline语法为何使用PipelinePipeline概念PipelineNodeStageStep Pipeline语法概述声明式Pipeline脚本式Pipeline Pipeline示例 参考 Pipeline 什么是Jenkins Pipeline Jenkins Pipeline是一套插件&#xff0c;它支持…

YOLOv9有效改进|使用空间和通道重建卷积SCConv改进RepNCSPELAN4

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 SCConv是一种即插即用的空间和通道重建卷积。 RepNCSPELAN4是YOLOv9中的特征提取模块&#xff0c;类似YOLOv5和v8中的C2f与C3模块。 …

国内chatgpt写作软件,chatgpt国内使用

随着人工智能技术的不断发展&#xff0c;国内涌现出了一些基于ChatGPT模型的写作软件&#xff0c;这些软件不仅能够实现智能化的文章写作&#xff0c;还支持批量生成各种类型的文章。本文将深入探讨国内ChatGPT写作软件&#xff0c;以及它们在批量文章创作方面的应用与优势。 C…

STM32作为SPI slave与主机异步通信

背景 最近被测试提了个BUG&#xff0c;说某款产品在用户按下前面板的按键后&#xff0c;对应的按键灯没有亮起来。前面板跟主机是通过SPI口通信&#xff0c;前面板是从机&#xff0c;从机想要主动发送消息&#xff0c;需要通过GPIO中断来通知主机&#xff1a; 上图前面板是ST…

php源码 单色bmp图片取模工具 按任意方式取模 生成字节数组 自由编辑点阵

http://2.wjsou.com/BMP/index.html 想试试chatGPT4生成&#xff0c;还是要手工改 php 写一个网页界面上可以选择一张bmp图片&#xff0c;界面上就显示这张bmp图片&#xff0c; 点生成取模按钮&#xff0c;在图片下方会显示这张bmp图片的取模数据。 取模规则是按界面设置的&a…

蓝桥ACM培训-搜索

前言&#xff1a; 今老师讲了了dfs,虽然我自己之前也自学了一点点&#xff0c;但我还是感觉做题并不是很顺&#xff0c;尤其是今天最后一题&#xff0c;我调试了一下午都没过&#xff0c;还需要积累经验呀。 正文&#xff1a; Problem:A 白与黑-搜索&#xff1a; #include &l…

DbSchema导出HTML/PDF版表结构

一、连接数据库 登录成功默认显示当前用户的所有资源&#xff08;表、视图、序列、方法、触发器等&#xff09;&#xff0c;如果不操作将导出此用户的全部信息。 至此连接数据库完成 二、表结构导出 本次不想给用户全部导出&#xff0c;只给导出几张&#xff0c;选择需要…

IPO观察丨“闷头做手机”的龙旗科技,如何拓宽价值边界?

提到手机代工&#xff0c;许多人会想起依靠iPhone订单发家的富士康。但近年来&#xff0c;随着国内智能手机供应链愈发成熟&#xff0c;龙旗科技、闻泰科技和华勤技术等一批国产手机代工厂快速崛起&#xff0c;业绩强劲增长之余&#xff0c;还迈进了二级市场。 比如&#xff0…

吴恩达deeplearning.ai:通过偏差与方差进行诊断

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 偏差与方差高偏差高方差合适的模型理解偏差与方差 总结 当你构建神经网络的时候&#xff0c;几乎没有人能够在一开始就将神经系统构建得十分完美。因此构建神经网络最重要的是直到…

BUGKU 头等舱

头等舱 打开环境&#xff0c;什么都没有&#xff0c;使用BP抓包&#xff0c;发送到重发器里&#xff0c;看响应得到flag

LeetCode 热题 100 | 图论(二)

目录 1 基础知识 1.1 什么是拓扑排序 1.2 如何进行拓扑排序 1.3 拓扑排序举例 2 207. 课程表 3 210. 课程表 II 菜鸟做题&#xff0c;语言是 C 1 基础知识 1.1 什么是拓扑排序 含义&#xff1a;根据节点之间的依赖关系来生成一个有序的序列。 应用&#xff1a…

详细了解C++中的namespace命名空间

键盘敲烂&#xff0c;月薪过万&#xff0c;同学们&#xff0c;加油呀&#xff01; 目录 键盘敲烂&#xff0c;月薪过万&#xff0c;同学们&#xff0c;加油呀&#xff01; 一、命名空间的理解 二、&#xff1a;&#xff1a;作用域运算符 三、命名空间&#xff08;namespace&…

勒索病毒最新变种.helper勒索病毒来袭,如何恢复受感染的数据?

尊敬的读者&#xff1a; 在数字时代&#xff0c;我们享受着科技带来的便利&#xff0c;但与此同时&#xff0c;网络安全威胁也在不断演变。其中&#xff0c;勒索病毒是一种极具破坏力的威胁&#xff0c;而.helper勒索病毒更是最新的变种之一。当你的文件被.helper勒索病毒加密…

SparkStreaming在实时处理的两个场景示例

简介 Spark Streaming是Apache Spark生态系统中的一个组件&#xff0c;用于实时流式数据处理。它提供了类似于Spark的API&#xff0c;使开发者可以使用相似的编程模型来处理实时数据流。 Spark Streaming的工作原理是将连续的数据流划分成小的批次&#xff0c;并将每个批次作…

redis04 发布与订阅

一种消息通信模式&#xff1a;发布者&#xff08;pub&#xff09;发布消息&#xff0c;订阅者&#xff08;sub&#xff09;接收消 息。 redis客户端可以订阅任意数量的频道。 发布订阅流程图 发布和订阅实现 打开两个窗口订阅channel1频道&#xff0c;再打开一个窗口向chan…