본문 바로가기

[unity] UI UIText에서 TextMeshProUGUI로 일괄 교체하는 방법

앤디가이 2022. 6. 28.

Unity에서 Scene 내 모든 UI Text 컴포넌트를 TextMeshProUGUI Text 컴포넌트로 일괄 교체하는 방법에 대해 알아보자.

 

유니티에서 2D 텍스트 표현에 있어 예전에 제작된 프로젝트 대부분이 유니티에서 제공하는 기본 UIText 컴포넌트로 구성되어 있다.

기본 UIText는 사용하기는 간편하지만, 확대 시 텍스트 깨짐, 텍스트 흐림 및 Batch 관리의 어려움 등의 단점이 존재하였다.

TextMeshProUGUI는 기존 UIText에 비해 폰트를 bake 해서 텍스쳐 1장으로 관리되기 때문에 퍼포먼스에 능하고, UIText의 단점을 보완되어 나온 라이브러리로 최근 프로젝트는 대부분 TextMeshProUGUI를 사용하고 있다.

 

 

1. 컴포넌트 교체 시 고려사항

그럼 텍스트 컴포넌트 교체 시 어떤 것들을 고려해야 할까?

1. 텍스트 내용

2. 폰트 정보

3. 폰트 크기

4. 폰트 스타일(볼드,이태릭 등)

5. AutoSize 여부

6. 컬러 정보

7. 정렬 옵션

 

위와 같은 기본적인 UIText 컴포넌트 내 요소들이 잘 이관되어야 한다.

그럼 위 내용을 바탕으로 자동화 할 수 있는 EditorClass를 제작해보자.

 

2. EditorClass 제작

프로젝트 내 Editor 폴더를 만든 후 UITextToTextMeshPro 에디터 클래스를 만들어 보자.

기존 UIText의 정보를 보관할 수 있는 클래스로 TextData를 내부 클래스로 정의해준다.

코드를 보면 다음과 같다.

using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;

namespace Modules.Util
{
    public class UITextToTextMeshPro : MonoBehaviour
    {
        //기존 UI Text 정보를 저장할 데이터 객체
        public class TextData
        {
            public string text; //문자열 정보
            public Color color; //텍스트 컬러 정보
            public TMP_FontAsset font; //폰트 정보
            public int fontSize; //폰트 사이즈 정보
            public int fontMaxSize; //폰트 최대 사이즈 정보(AutoSize 시)
            public bool autoSize; //AutoSize 여부
            public TextAlignmentOptions alignOptions; //정렬 옵션
            public FontStyles fontStyles; //폰트 스타일 옵션

        }

        //폰트 경로 설정.
        public const string PATH_FONT_TEXTMESHPRO_JALNAN = "Assets/Fonts/Jalnan SDF.asset";

        [MenuItem("CustomMenu/Text/UITextToTextMeshProUGUI(UI 텍스트를 TextMeshProUGUI 텍스트로 교체함")]
        public static void ChangeTextMeshProUGUI()
        {
            GameObject[] rootObj = GetSceneRootObjects();

            for (int i = 0; i < rootObj.Length; i++)
            {
                GameObject gbj = (GameObject)rootObj[i] as GameObject;
                Component[] com = gbj.transform.GetComponentsInChildren(typeof(Text), true);
                foreach (Text txt in com)
                {

                    TextData data = ConvertTextData(txt);
                    GameObject obj = txt.gameObject;
                    //기존 Text 컴포넌트 삭제
                    DestroyImmediate(txt.gameObject.GetComponent<Text>());
                    if (!obj.GetComponent<TextMeshProUGUI>())
                    {
                        TextMeshProUGUI newGUIText = obj.AddComponent<TextMeshProUGUI>();
                        newGUIText.text = data.text;
                        newGUIText.font = data.font;
                        newGUIText.fontSize = data.fontSize;
                        newGUIText.color = data.color;
                        newGUIText.enableAutoSizing = data.autoSize;
                        newGUIText.fontSizeMax = data.fontMaxSize;
                        newGUIText.alignment = data.alignOptions;
                        newGUIText.fontStyle = data.fontStyles;
                    }
                }
            }
        }

        /// <summary>
        /// UGUI Text 정보를 TextMeshPro Text 정보로 Convert 한다.
        /// </summary>
        /// <param name="text">UGUI Text</param>
        /// <returns>TextMeshProUGUI TextData</returns>
        private static TextData ConvertTextData(Text text)
        {
            TextData data = new TextData();
            data.text = text.text;
            data.color = text.color;
            data.font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(PATH_FONT_TEXTMESHPRO_JALNAN);
            data.fontSize = text.fontSize;
            data.fontMaxSize = text.resizeTextMaxSize;
            data.autoSize = text.resizeTextForBestFit;
            switch(text.alignment)
            {
                case TextAnchor.LowerCenter:
                    data.alignOptions = TextAlignmentOptions.Bottom;
                    break;
                case TextAnchor.LowerLeft:
                    data.alignOptions = TextAlignmentOptions.BottomLeft;
                    break;
                case TextAnchor.LowerRight:
                    data.alignOptions = TextAlignmentOptions.BottomRight;
                    break;
                case TextAnchor.MiddleCenter:
                    data.alignOptions = TextAlignmentOptions.Midline;
                    break;
                case TextAnchor.MiddleLeft:
                    data.alignOptions = TextAlignmentOptions.Left;
                    break;
                case TextAnchor.MiddleRight:
                    data.alignOptions = TextAlignmentOptions.Right;
                    break;
                case TextAnchor.UpperCenter:
                    data.alignOptions = TextAlignmentOptions.Top;
                    break;
                case TextAnchor.UpperLeft:
                    data.alignOptions = TextAlignmentOptions.TopLeft;
                    break;
                case TextAnchor.UpperRight:
                    data.alignOptions = TextAlignmentOptions.TopRight;
                    break;
            }
            switch(text.fontStyle)
            {
                case FontStyle.Bold:
                    data.fontStyles = FontStyles.Bold;
                    break;
                case FontStyle.BoldAndItalic:
                case FontStyle.Italic:
                    data.fontStyles = FontStyles.Italic;
                    break;
                default:
                    data.fontStyles = FontStyles.Normal;
                    break;
            }
            
            return data;
        }

        /// <summary>
        /// 모든 최상위 Root의 GameObject를 받아옴.
        /// </summary>
        /// <returns></returns>
        private static GameObject[] GetSceneRootObjects()
        {
            Scene currentScene = SceneManager.GetActiveScene();

            return currentScene.GetRootGameObjects();
        }
    }
}

 

코드에서 ChangeTextMeshProUGUI() 함수를 통해 대부분의 기능이 실행된다.

실행 흐름은 다음과 같다.

1. Scene의 모든 Root 오브젝트를 검색하여 배열로 저장

2. Root 오브젝트를 Loop 하며 Text 컴포넌트 검출

3. Text 컴포넌트 정보를 TextData 에 저장

4. Text 컴포넌트 삭제

5. TextMeshProUGUI 컴포넌트 추가

6. TextMeshProUGUI 컴포넌트에 TextData 정보 입력

 

 

3. 결과 확인

결과 영상을 보면 UIText 컴포넌트가 TextMeshProUGUI 컴포넌트로 교체되며, 정보도 같이 이관되는 걸 볼 수 있다.

테스트 결과 폰트 자간등의 영향으로 약간의 위치 차이가 발생할 순 있을 것 같다.

 

 

결과 화면

댓글