【unity】TextMeshPro文本抖动效果

文本抖动效果

前言

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

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博客


__EOF__

本文作者OtusScops
本文链接https://www.cnblogs.com/OtusScops/p/17480963.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   AshScops  阅读(1178)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2021-06-14 【unity2D】设计模式-单例模式Singleton
点击右上角即可分享
微信分享提示