using UnityEngine; using UnityEngine.TextCore; using System.Collections; using System.Collections.Generic; namespace TMPro { [DisallowMultipleComponent] public class TMP_SpriteAnimator : MonoBehaviour { private Dictionary m_animations = new Dictionary(16); //private bool isPlaying = false; private TMP_Text m_TextComponent; void Awake() { m_TextComponent = GetComponent(); } void OnEnable() { //m_playAnimations = true; } void OnDisable() { //m_playAnimations = false; } public void StopAllAnimations() { StopAllCoroutines(); m_animations.Clear(); } public void DoSpriteAnimation(int currentCharacter, TMP_SpriteAsset spriteAsset, int start, int end, int framerate) { bool isPlaying; // Need to add tracking of coroutines that have been lunched for this text object. if (!m_animations.TryGetValue(currentCharacter, out isPlaying)) { StartCoroutine(DoSpriteAnimationInternal(currentCharacter, spriteAsset, start, end, framerate)); m_animations.Add(currentCharacter, true); } } IEnumerator DoSpriteAnimationInternal(int currentCharacter, TMP_SpriteAsset spriteAsset, int start, int end, int framerate) { if (m_TextComponent == null) yield break; // We yield otherwise this gets called before the sprite has rendered. yield return null; int currentFrame = start; // Make sure end frame does not exceed the number of sprites in the sprite asset. if (end > spriteAsset.spriteCharacterTable.Count) end = spriteAsset.spriteCharacterTable.Count - 1; // Get a reference to the current character's info TMP_CharacterInfo charInfo = m_TextComponent.textInfo.characterInfo[currentCharacter]; int materialIndex = charInfo.materialReferenceIndex; int vertexIndex = charInfo.vertexIndex; TMP_MeshInfo meshInfo = m_TextComponent.textInfo.meshInfo[materialIndex]; float baseSpriteScale = spriteAsset.spriteCharacterTable[start].scale * spriteAsset.spriteCharacterTable[start].glyph.scale; float elapsedTime = 0; float targetTime = 1f / Mathf.Abs(framerate); while (true) { if (elapsedTime > targetTime) { elapsedTime = 0; // Return if sprite was truncated or replaced by the Ellipsis character. char character = m_TextComponent.textInfo.characterInfo[currentCharacter].character; if (character == 0x03 || character == 0x2026) { m_animations.Remove(currentCharacter); yield break; } // Get a reference to the current sprite TMP_SpriteCharacter spriteCharacter = spriteAsset.spriteCharacterTable[currentFrame]; // Update the vertices for the new sprite Vector3[] vertices = meshInfo.vertices; Vector2 origin = new Vector2(charInfo.origin, charInfo.baseLine); float spriteScale = charInfo.scale / baseSpriteScale * spriteCharacter.scale * spriteCharacter.glyph.scale; Vector3 bl = new Vector3(origin.x + spriteCharacter.glyph.metrics.horizontalBearingX * spriteScale, origin.y + (spriteCharacter.glyph.metrics.horizontalBearingY - spriteCharacter.glyph.metrics.height) * spriteScale); Vector3 tl = new Vector3(bl.x, origin.y + spriteCharacter.glyph.metrics.horizontalBearingY * spriteScale); Vector3 tr = new Vector3(origin.x + (spriteCharacter.glyph.metrics.horizontalBearingX + spriteCharacter.glyph.metrics.width) * spriteScale, tl.y); Vector3 br = new Vector3(tr.x, bl.y); vertices[vertexIndex + 0] = bl; vertices[vertexIndex + 1] = tl; vertices[vertexIndex + 2] = tr; vertices[vertexIndex + 3] = br; // Update the UV to point to the new sprite Vector2[] uvs0 = meshInfo.uvs0; Vector2 uv0 = new Vector2((float)spriteCharacter.glyph.glyphRect.x / spriteAsset.spriteSheet.width, (float)spriteCharacter.glyph.glyphRect.y / spriteAsset.spriteSheet.height); Vector2 uv1 = new Vector2(uv0.x, (float)(spriteCharacter.glyph.glyphRect.y + spriteCharacter.glyph.glyphRect.height) / spriteAsset.spriteSheet.height); Vector2 uv2 = new Vector2((float)(spriteCharacter.glyph.glyphRect.x + spriteCharacter.glyph.glyphRect.width) / spriteAsset.spriteSheet.width, uv1.y); Vector2 uv3 = new Vector2(uv2.x, uv0.y); uvs0[vertexIndex + 0] = uv0; uvs0[vertexIndex + 1] = uv1; uvs0[vertexIndex + 2] = uv2; uvs0[vertexIndex + 3] = uv3; // Update the modified vertex attributes meshInfo.mesh.vertices = vertices; meshInfo.mesh.uv = uvs0; m_TextComponent.UpdateGeometry(meshInfo.mesh, materialIndex); if (framerate > 0) { if (currentFrame < end) currentFrame += 1; else currentFrame = start; } else { if (currentFrame > start) currentFrame -= 1; else currentFrame = end; } } elapsedTime += Time.deltaTime; yield return null; } } } }