うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】TextMeshPro で一文字ずつ Animation させる

using System.Collections;
using TMPro;
using UnityEngine;
 
[RequireComponent(typeof(TextMeshProUGUI))]
public class TextMove : MonoBehaviour
{
    [SerializeField]
    private float _interval = 0.25f;
    
    [SerializeField]
    private float _moveTime = 0.5f;
    
    [SerializeField]
    private Vector2 _moveOffset = new Vector2(0, 1f);
    
    private TMP_MeshInfo[] cachedMeshInfo;
 
    private IEnumerator Start()
    {
        var component = GetComponent<TMP_Text>();
        
        component.ForceMeshUpdate();
        
        var textInfo = component.textInfo;
        
        var cc = textInfo.characterCount;
        
        cachedMeshInfo = textInfo.CopyMeshInfoVertexData();
        
        while (true)
        {
            for (var characterIndex = 0; characterIndex < cc; characterIndex++)
            {
                var charInfo = textInfo.characterInfo[characterIndex];
                if (charInfo.isVisible)
                {
                    StartCoroutine(UpdatePosition(characterIndex));
                    
                    yield return new WaitForSeconds(_interval);
                }
            }
        }
    }
 
    private IEnumerator UpdatePosition(int index)
    {
        var component = GetComponent<TMP_Text>();
        
        var textInfo = component.textInfo;
        var charInfo = textInfo.characterInfo[index];
        var materialIndex = charInfo.materialReferenceIndex;
        var vertexIndex = charInfo.vertexIndex;
        var offset = Vector3.zero;
        
        var current = 0f;
        while (true)
        {
            var t = Mathf.InverseLerp(0, _moveTime, current);
            t = Mathf.InverseLerp(t >= 0.5f ? 1 : 0, 0.5f, t);
            Update(t);
            
            current += Time.deltaTime;
            if (current >= _moveTime)
            {
                Update(0);
                yield break;
            }
 
            yield return null;
        }
 
        void Update(float t)
        {
            for (var j = 0; j < 2; j++)
            {
                offset[j] = Mathf.Lerp(0, _moveOffset[j], t);
            }
            
            var sourceVertices = cachedMeshInfo[materialIndex].vertices;
            var destinationVertices = textInfo.meshInfo[materialIndex].vertices;
            for (var i = 0; i < 4; i++)
            {
                var meshIndex = vertexIndex + i;
                destinationVertices[meshIndex] = sourceVertices[meshIndex] + offset;
            }
            textInfo.meshInfo[materialIndex].mesh.vertices = destinationVertices;
            component.UpdateGeometry(textInfo.meshInfo[materialIndex].mesh, materialIndex);
        }
    }
}