首页 > 其他分享 >【unity】TextMeshPro文本抖动效果

【unity】TextMeshPro文本抖动效果

时间:2023-06-14 17:58:18浏览次数:57  
标签:字符 int text vertices meshInfo TextMeshPro unity textInfo 文本

文本抖动效果

前言

在部分电子游戏中,当角色处于狂喜、紧张或恐惧等激动情绪时,角色对话框中的文字会触发抖动等效果,这为游戏增色不少,如下。

image

当我在网上查找相关资料时,没找到相关的实现,也可能是我搜索的关键词不对。

总之今天来实现一下这个效果。

实现思路

目标效果是:在同一帧的动效中,文本中的每个字符各自随机方向偏移了一小段距离。

传统的Text组件我不清楚能不能成,但是TextMeshPro一定能成,因为TextMeshPro中的文本渲染是基于Mesh的,只要能拿到每个字符对应的Mesh顶点数据,就能单独给每个字符设置位置、颜色等数据。如果不明白的话去补一下Mesh相关知识就好。

实现思路如下:

  1. 获取TextMeshPro中的顶点数组和每个字符。
  2. 遍历每个字符,对每一个字符,都随机生成偏移量,并将该偏移量应用在这个字符对应的所有顶点数据上。
  3. 更新组件渲染。

可能的困难

我们需要在同一帧内随机生成各个字符的偏移,这些偏移要保证各不相同。

在同一帧中,除非改变传入的minmax的值,否则无论调用多少次,引擎中的Random.Range(min, max) 的返回值都会是同一个数。

解决方案:基于内存地址,使用C#System.Random,详情见->Unity并发取随机导致相同解决方法

代码实现

using System;
using System.Collections;
using System.Runtime.InteropServices;
using TMPro;
using UnityEngine;

public class FontSingleBeat : MonoBehaviour
{
    TextMeshProUGUI text;
    /// <summary>
    /// 速度(时间间隔)
    /// </summary>
    public float shakeSpeed = 0.05f;

    /// <summary>
    /// 幅度
    /// </summary>
    public float shakeAmount = 1f;

    private Vector3[] m_rawVertex;

    private void Awake()
    {
        text = this.GetComponent<TextMeshProUGUI>();
        text.ForceMeshUpdate();
        
    }

    private void Start()
    {
        GetRawVertex();
        StartCoroutine(ShakeText());
    }

    private void GetRawVertex()
    {
        if(text.textInfo.characterCount > 0)
        {
            TMP_CharacterInfo charInfo = text.textInfo.characterInfo[0];
            TMP_MeshInfo meshInfo = text.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);
            }
        }
        else
        {
            Debug.LogError("GetRawVertex Failed.");
        }
    }

    IEnumerator ShakeText()
    {
        while (true)
        {
            for (int i = 0; i < text.textInfo.characterCount; i++)
            {
                // 获取字符信息和MeshInfo
                TMP_CharacterInfo currentCharInfo = text.textInfo.characterInfo[i];
                TMP_MeshInfo meshInfo = text.textInfo.meshInfo[currentCharInfo.materialReferenceIndex];
                int vertexCount;
                if (i < text.textInfo.characterCount - 1)
                {
                    TMP_CharacterInfo nextCharInfo = text.textInfo.characterInfo[i + 1];
                    vertexCount = nextCharInfo.vertexIndex - currentCharInfo.vertexIndex;
                }
                else
                {
                    vertexCount = meshInfo.vertices.Length - currentCharInfo.vertexIndex;
                }

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

                // 随机生成位移量
                int mult = 100;
                float xOffset = GetRandom((int)-shakeAmount * mult, (int)shakeAmount * mult, i);
                float yOffset = GetRandom((int)-shakeAmount * mult, (int)shakeAmount * mult, i + text.textInfo.characterCount);
                Vector3 offset = new Vector3(xOffset, yOffset) / 100f;
                //print(xOffset + ", " + yOffset);

                // 顶点偏移
                Vector3[] vertices = meshInfo.vertices;
                for (int j = vertexIndex; j < vertexIndex + vertexCount; j++)
                {
                    vertices[j] = m_rawVertex[j] + offset;
                }

                // 刷新单个字符
                //text.SetVerticesDirty();
                //text.SetMaterialDirty();
            }

            text.UpdateVertexData();
            yield return new WaitForSeconds(shakeSpeed);
        }
    }


    /// <summary>
    /// 获取基地址的
    /// </summary>
    /// <param name="o"></param>
    /// <returns></returns>
    public int GetMemory(object o)
    {
        GCHandle h = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
        IntPtr addr = GCHandle.ToIntPtr(h);
        return int.Parse(addr.ToString());
    }

    /// <summary>
    /// 产生随机数
    /// 调用它就可以产生你要的随机数了,如果有需求可以自己重载
    /// </summary>
    /// <param name="min">最小值</param>
    /// <param name="Max">最大值</param>
    /// <returns></returns>
    public float GetRandom(int min, int Max, int iSeed)
    {
        System.Random rd = new System.Random(GetMemory(iSeed));
        return (rd.Next(min, Max));
    }
}

最终效果

上面一排是目标效果;下面一排是文本整体偏移抖动。

image

参考资料

Unity并发取随机导致相同解决方法_fairen的博客-CSDN博客

标签:字符,int,text,vertices,meshInfo,TextMeshPro,unity,textInfo,文本
From: https://www.cnblogs.com/OtusScops/p/17480963.html

相关文章

  • ma系列之-7-文本处理工具grep egrep 和正则
      1概念: grep概念:根据模式搜索文本,并将符合模式的文本行显示出来。 globalreserchbyexpressiongrep的特点:就是在某个行中找只要符合匹配的行就可以,就是做部分匹配的,不是整个单词匹配,显示的是整行数据,重点展示的是匹配到的那个字段。 grep使用的模式Pattern组成:由文本......
  • 一个在线显示doc文本的实例
    <spanstyle="font-family:Arial,Helvetica,sans-serif;background-color:rgb(255,255,255);">最近带着一对攻城狮给客户做一个web平台系统,在与客户做需求分析的过程中,发现客户有个需求痛点,那就是希望能在web上直接浏览doc文本的内容。原来的老平台在显示doc文本时,有很多问......
  • 一个android文本比对app的实现(二)--界面
    <spanstyle="font-family:Arial,Helvetica,sans-serif;background-color:rgb(255,255,255);">继上一篇博文大致介绍了这一简单但有点用处的app后(详情:</span><spanstyle="color:rgb(51,51,51);font-family:Arial;font-size:14px;line-height:26px;b......
  • 一个android 文本比对App的实现(一)
    做c++开发很多年了,从早年windowsvc6.0做客户端程序开发,这些年后台流媒体服务器后台开发。随着时代变迁,移动互联逐渐兴起,直到现在,移动互联的风头早已盖过传统互联网应用,因而传统后台开发似乎日渐式微。如今要找工作的话,android,IOS等开发的职位不但数量远远多于c++,而且报酬也要比c+......
  • Unity3D学习笔记(二)创建地形和漫游
    七月3201212:35上午上一章粗略介绍了一下Unity游戏引擎的概念定义和界面功能,这次就来实践一下。我们的目标是没有蛀牙(误),目标是创建一个地形,上面有山脉和盆地,然后再放置一个人物,以第一人称的视角来漫游、观察我们所创建的世界。 在开始设计游戏之前我们需要先重新......
  • Unity3D学习笔记(一)界面介绍
    六月2020128:05下午从开始学习Unity到现在已经过去近三个月了,期间零零散散地在网上找教程、实例,感觉印象不够深刻。好多知识点不是被忽略了,就是被遗忘了。有幸在六一儿童节的时候发现了3DBuzz的基础视频教程,犹如介绍所言,几乎详细到每个菜单和按钮。为了部落(误),为......
  • Canvas_绘制线段、圆形、文本、图像、视频、处理图像数据
    Canvas_绘制线段、圆形、文本、图像、视频、处理图像数据绘制线段varcanvas1=document.querySelector("#canvas1");varctx=canvas1.getContext("2d");//设置开始路径ctx.beginPath()//设置绘制的起始点ctx.moveTo(50,50);//设置经过某个位置ctx.lineTo(50,30......
  • R语言文本挖掘、情感分析和可视化哈利波特小说文本数据|附代码数据
    全文下载链接:http://tecdat.cn/?p=22984最近我们被客户要求撰写关于文本挖掘的研究报告,包括一些图形和统计输出。一旦我们清理了我们的文本并进行了一些基本的词频分析,下一步就是了解文本中的观点或情感。这被认为是情感分析,本教程将引导你通过一个简单的方法来进行情感分析。......
  • 中文分词接口,中文文本分割
    中文分词接口一、接口介绍将长段中文智能切开,分隔。用于中文词义分析、推广营销、用户消费捕捉等场景,如全文检索的时候需要把文本切词;对博客标题进行分词,提取其中的名词作为文章关键词;对用户搜索条件进行分词,提取其中关键词语进行搜索。二、功能体验三、产品特点四、API文......
  • MusicGen:将文本和旋律转化为音乐
    Meta的MusicGen可以根据文本提示生成短小的新音乐片段,并可选择与现有旋律对齐。与今天的大多数语言模型一样,MusicGen基于Transformer模型。就像语言模型预测句子中的下一个字符一样,MusicGen预测音乐作品中的下一个部分。研究人员使用Meta的EnCodec音频标记器将音频数据......