요즘 게임들을 보면 바들바들 떨리는 글자가 종종 보인다.





a64b18ad230e76a167b9f68b12d21a1d64118cdc1cc647


( 슬레이 더 스파이어 이벤트 중 볼 수 있는 떨리는 글자 효과 )





a04020ad233676a167b9f68b12d21a1d968fcec5ef0799


( 커멘더 퀘스트에서 볼 수 있는 다양한 글자 효과 )





이러한 글자 효과를 넣으면 생각이 상당히 이쁘게 보인다!






a65f04ac3532782da9535d46d69f233497cf89fc561726be0194cabd1ced


( 다음은 필자가 만든 게임에 넣은 글자 효과 예시, 만족도가 높다! )




이렇게 한 텍스트 오브젝트 안의 몇 가지 단어를 특정하여 효과를 넣을 수 있는데,


필자가 구현한 방법을 요약하자면 다음과 같다.




1. 색 효과 ( 컬러 태그로 감싸기 )




색 효과는 비교적 간단한 편인데, 컬러 태그로 감싸주기만 하면 된다!


다만, 컬러 태그 양식을 맞춰서 감싸주어야 한다.




   
    // 1. 문자열 래핑
    public static string WrapString(string text, Color color)
    {
        return $"<color={ToHex(color)}>{text}</color>";
    }

    // 2. 컬러 태그 변환
    private static string ToHex(Color color, bool includeAlpha = false)
    {
        Color32 c = color;
        if (includeAlpha)
            return $"#{c.r:X2}{c.g:X2}{c.b:X2}{c.a:X2}";
        else
            return $"#{c.r:X2}{c.g:X2}{c.b:X2}";
    }


// 3. 활용
    string description = "아주 중요한 설명입니다!";
    TextMeshProUGUI textMeshProUGUI;
    textMeshProUGUI.text = description.Replace("중요한", ColorUtils.WrapString("중요한", Color.red));




다음의 함수를 Util 클래스 만들어서 활용해주면 아주 쉽게, 감싸줄 수 있다!


이용할 때에는 다음과 같은 방식, 혹은 자기만의 방식으로 활용하면 된다!




2. 문자 애니메이션 효과 ( 동적 움직임 및 색상 변화 효과 ) 




필자가 구현한 문자 애니메이션 효과 구현 순서는 다음과 같다.




2-1. 문자 위치 찾기




a14134aa3c2a76b660b8f68b12d21a1d4efbb86da9




원하는 문자가 "꿈틀"이라면, text  "꿈틀"이라는 텍스트 위치를 찾는다.


필자는 for문 돌려서 인덱스 찾음.




2-2. 문자 정점과 중심점 찾기




a17d25aa252207e87eb1d19528d52703df41e4488883




상하로 이동을 주든 떨림을 주든 하기 위해선,


해당 문자를 사각형이라고 생각하고 각 꼭짓점의 정보가 필요하다.


문자열이라면 각각의 문자에 대해서 동일한 효과를 주는 방식.






    // 1. TMP 컴포넌트의 원하는 문자 정보 접근
    TextMeshProUGUI tmpText;
    TextInfo textInfo = tmpText.textInfo;
    TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; // i는 문자 위치

    // 2. 문자 정보를 통해 각 정점 관련 정보 획득
    int vi = charInfo.vertexIndex; // 정점 시작 index
    int mi = charInfo.materialReferenceIndex; // metarial 정보
    Vector3[] verts = textInfo.meshInfo[mi].vertices; // 정점 정보들
    Color32[] colors = textInfo.meshInfo[mi].colors32; // 색 정보

    // 3. 중심점
    Vector3 center = (verts[vi] + verts[vi + 2]) / 2;

    // 4. 정점 좌표를 중심점 기준으로 변경, 원래는 캔버스 원점 기준
    for (int j = 0; j < 4; j++) verts[vi + j] -= center;

    // 5. 효과 적용, 이후 설명
ApplyShake(ref verts, vi);

    // 6. 정점 좌표를 돌려놓기
    for (int j = 0; j < 4; j++) verts[vi + j] += center;




조금, 복잡해보이지만 아주 간단하다.


1. TMP 컴포넌트를 통해 원하는 문자 정보 (charInfo) 찾기


2. 문자 정보에서 정점 정보 얻어오기 + 중심점




2-3. 애니메이션 효과 주기 ( 변화된 정점 정보 적용 )




필요한 정보를 얻었다면, 애니메이션  효과를 주는 건 간단하다.





ApplyShake(ref verts, vi);

    // 정점 정보 변화
    private void ApplyShake(ref Vector3[] vertices, int vi)
    {
        float x = (Mathf.PerlinNoise(0.1f, Time.unscaledTime * 8f) - 0.5f) * 2f;
        float y = (Mathf.PerlinNoise(0.1f + 100f, Time.unscaledTime * 8f) - 0.5f) * 2f;
        Vector3 offset = new Vector3(x, y, 0f) * shakeIntensity;
        for (int j = 0; j < 4; j++) vertices[vi + j] += offset;
    }

    // 변화된 정점 정보 적용
for (int i = 0; i < textInfo.meshInfo.Length; i++)
    {
        textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
        textInfo.meshInfo[i].mesh.colors32 = textInfo.meshInfo[i].colors32;
        tmpText.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
    }




이렇게 정점 정보를 받아와서 약간의 변화를 준 뒤, 변화된 정점 정보를 적용 시켜주는 방식으로 떨림을 구현할 수 있다!


복잡시럽게 붙어있는 수치들은 세부 조정한 값이고,


핵심은 문자의 정점 위치를 조정한 뒤 그걸 TextMesh에 다시 적용시켜 주는 것!





    private void ApplyRainbow(ref Color32[] colors, int vi)
    {
        Color c = Color.HSVToRGB((Time.unscaledTime * 0.5f + 0.05f) % 1f, 1f, 1f);
        for (int j = 0; j < 4; j++) colors[vi + j] = c;
    }



이렇게 정점의 색 정보를 바꾸면,


동적 색상 변화도 가능하다!


참고로, 이러한 변화 및 적용은 Update에서 매번 호출해서 적용 하는 것.




요약 :


문자 정점 정보 찾기 => 문자 정점 위치/색상 조절 => 변화된 정점 정보 적용




3. 애니메이션 효과



이러한 문자 효과는 여러개 중첩 적용 가능하다!




a64e2cad1b2ab275aaf1d1bc10f11a39d9ba638277c9c735bc11



짜잔!



다들, 소소하지만 이쁜 글자 효과 하나씩 넣는 것은 어떨까,,,??




4. 마치며




a76530aa1b22782b866b5b59f79f233426f27119b12ce64faed006a1a362



다음에는 문자에 효과를 넣는 것처럼,


오브젝트가 아니라 TextMesh의 문자에 상호작용 하여 툴팁 보여주는 방법에 대한 글을 써볼 생각. 





a64e2cad1b2e76a167b9f68b12d21a1d910fabef9f30fa42


마지막은 만들고 있는 게임,,