유니티 게임 Localization (현지화) 작업

2025. 11. 25. 02:03·기타

유니티는 공식적으로 Localization을 지원하긴 하나
실력을 늘리고 싶어 직접 만들어 출시 준비중인 게임에 적용해보았습니다.

 

1. 언어 별 폰트 구하기

무료 폰트로 범용성, 가독성이 좋은 Nato Sans CJK를 추천하지만,

게임 특성상 둥글둥글한 폰트가 필요하여 언어별 다른 무료 폰트 찾음

 

TMPro를 쓸 것이기에 받은 폰트로 폰트 에셋 생성

중국어 폰트를 생성할 때는 해당 옵션을 사용하였고, 생성한 폰트 에셋에는 Atlas Population Mode = Dynamic 설정

그 중에 중국어 폰트가 너무 얇게 나오고 폰트의 Weight을 조절하여 폰트 파일로 재추출하는데는 유로 프로그램이 필요했기에 가난한 개발자 팀으로써는 부담이 되어 다른 방법을 찾음

아래 코드들에서 중국어 폰트일 때 TMP_Text의 Outline 두께 및 색상을 조절하여 해당 글씨체처럼 보이게끔 조치
해당 포스팅으로 공부하는 분은 아래 코드에서 Outline 관련은 제외하고 보길 권장

 

 

 

현지화 파일 구조. 이하 각 스크립트 및 기능 설명

2. LocalizationManager

게임 중 모든 텍스트 관련해서 접근이 가능하게 싱글톤

현지화 관련된 핵심 기능들이 담겨 있는데,

 

(1) 초기 언어 설정: 처음 실행 시 스팀, 시스템 os 언어 설정을 읽어와 해당하는 언어를 기본으로 사용하게끔

(2) 언어 설정값 반영: 설정에서 언어 선택 시 해당 메서드 호출. 설정값 기억, 언어에 맞는 폰트 설정, 등록된 언어 변경 이벤트들을 실행하여 언어 설정값에 맞게 표시 문자열 변경

(3) 번역 문자열 반환 : 현재 언어 옵션의 key에 해당하는 문자 값을 반환 >> 런타임 도중 텍스트를 변경해야 할 경우 사용

스크립트로 문자열을 직접 반환받아 제어할 경우, 아래와 같이 enum 항목 명칭을 key로 사용

string weaponName = LocalizationManager.instance.GetText(Weapon_Keys.Weapon_Shooter_Name.ToString());

(4) 폰트 설정 : 매개변수로 받는 TMP_Text 타입의 폰트를 언어에 맞게 교체 및 필요한 옵션 설정

using System.Collections.Generic;
using System.IO;
using UnityEngine;
using TMPro;

// 스팀에서 플레이 시 스팀 언어 설정대로 기본 언어를 설정하기 위해 추가
#if USE_STEAM
using Steamworks;
#endif

// 스팀에서 어떤 언어인지 반환하는 문자열을 언어로 설정
// !주의! : LocalizedValue 클래스와 언어 인덱스 순서를 동일하게 하기
enum LanguageCode
{
    koreana, // 한국어
    english, // 영어
    schinese, // 중국어(간체)
    tchinese, // 중국어(번체)
    japanese, // 일어
    russian, // 러시아어
    german, // 독일어
    french, // 프랑스어
    italian, // 이탈리아어
    spanish, // 스페인어
    polish, // 폴란드어
    portuguese, // 포르투갈어(유럽) >> 브라질어와 따로 번역하는 게 안전
    unknown
}

/* !!! 주의 !!!
/////////////////////////////////////////////////////////////////

 1. 컨텐츠 추가 시,
    .json 파일에 key, value 값을 추가하면서
    enum lacalizeKeys에 해당 key 값을 포함해둬야 함

 2. Assets.StreamingAssets 폴더
    유니티에서 특별한 기능을 맡는 폴더(Assets.Resources와 유사)
    명칭 변경/폴더 이동 시 이하 코드가 제대로 동작하지 않음

    필요하다면 Assets.StreamingAssets 폴더 내부에 하위 폴더를 만들어서 세분화하고,
    LoadLanguage()의 string path 참조 경로를 알맞게 바꿔주는 것을 추천

//////////////////////////////////////////////////////////////////
*/

// 현지화 데잍터의 딕셔너리(키, 값 페어)
[System.Serializable]
public class LocalizationData
{
    public string key;
    public LocalizedValue value;
}

// 현지화 데이터들의 배열(모음)
[System.Serializable]
public class LocalizationFile
{
    public LocalizationData[] items;
}

// 언어 별 value 나누는 키워드
[System.Serializable]
public class LocalizedValue
{
    public string ko;
    public string en;
    public string zh_CN;
    public string zh_TW;
    public string jp;
}

// 인스펙터 정리 + 작업 효율을 위한 커스텀 에디터를 쓰기 위해 사용
// 텍스트
[System.Serializable]
public class LocalizeKeySelector
{
    public LocalizeCategory category;
    public string key; // 실제 선택된 키 이름 (문자열로 저장)
}

// 드롭다운
[System.Serializable]
public class LocalizeDropDownKeysSelector
{
    public LocalizeKeySelector[] categories; // 실제 선택된 키 이름 (문자열로 저장)
}

public class LocalizationManager : MonoBehaviour
{
    #region 싱글톤
    // 게임 컨텐츠들 어디서나 언어에 따른 텍스트들에 접근하기 용이하게 싱글톤
    public static LocalizationManager instance {  get; private set; }

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
            InitLanguage();
            LoadLanguage();
        }
        else
            Destroy(gameObject);
    }
    #endregion

    #region 현지화
    Dictionary<string, LocalizedValue> localizedText;

    // 각 인덱스가 어느 언어에 해당하는지는 GetText() 내 switch 구문 참고
    public int languageIndex {  get; private set; }

    readonly string failText = "Translation Failed";
    readonly string fileName = "localization.json";
    readonly string languageSetting = "language";

    // 한국어, 영어 폰트 : Paperlogy-9Black SDF
    public TMP_FontAsset font_KE;
    // 중국어 간체 폰트
    public TMP_FontAsset font_zh_CN;
    // 중국어 번체 폰트
    public TMP_FontAsset font_zh_TW;

    public void SetLanguage(int index)
    {
        languageIndex = index;
        // 설정한 언어 옵션으로 다음에 실행되게끔 저장
        PlayerPrefs.SetInt(languageSetting, languageIndex);
        // 씬 시작 때 한번만 폰트를 변화하기에 옵션을 바꿀 때
        // 해당 씬 내 모든 텍스트의 폰트 일괄 변경 기능 추가
        TextMeshProUGUI[] tmp_texts = FindObjectsOfType<TextMeshProUGUI>(true);
        for (int i = 0; i < tmp_texts.Length; i++)
        {
            GetFont(tmp_texts[i]);
        }
        // 언어 변경 이벤트 호출
        OnLanguageChanged?.Invoke();
    }

    // 언어 변경 시 이벤트
    public static event System.Action OnLanguageChanged;

    // 언어 기본 설정
    void InitLanguage()
    {
        // 1, PlayerPrefs에 저장된 언어(기존 선택/플레이했던 언어)
        if(PlayerPrefs.HasKey(languageSetting))
        {
            languageIndex = PlayerPrefs.GetInt(languageSetting);
            return;
        }
        // 아래는 처음 실행할 때만 실행
#if USE_STEAM
// 2. 스팀에서 설정한 언어(게임을 해당 언어로 플레이하고 싶은 유저이기에 스팀 언어를 따라가는 게 맞음)
// 스팀 초기화가 되었는지 체크 >> 순서에 문제가 있다면, PlayerSettings에서 SteamManager.Initialized 이후에 해당 스크립트가 실행되게끔 순서 지정
        if (SteamManager.Initialized)
        {
            // 스팀 클라이언트에서 사용자가 설정한 언어 읽어오기
            string steamLanguage = SteamApps.GetCurrentGameLanguage();
            switch(steamLanguage)
            {
                // 번역한 언어들을 쓰는지 체크
                case SteamLanguage.koreana.ToString():
                    languageIndex = (int)LanguageCode.koreana;
                    break;
                case SteamLanguage.english.ToString():
                    languageIndex = (int)LanguageCode.english;
                    break;
                case SteamLanguage.schinese.ToString():
                    languageIndex = (int)LanguageCode.schinese;
                    break;
                case SteamLanguage.tchinese.ToString():
                    languageIndex = (int)LanguageCode.tchinese;
                    break;
                case SteamLanguage.japanease.ToString():
                    languageIndex = (int)LanguageCode.japanese;
                    break;
                // 어떠한 언어도 매칭되지 않으면 공통어로 많이 쓰는 영어로 설정
                default:
                    languageIndex = (int)LanguageCode.english;
                    break;
            }
            PlayerPrefs.SetInt(languageSetting, languageIndex);
            return;
        }
#endif
        // 3. 시스템 OS에서 설정된 언어(스토브, 스팀 초기화가 안되었을 때)
        SystemLanguage systemLanguage = Application.systemLanguage;
        switch (systemLanguage)
        {
            case SystemLanguage.Korean:
                languageIndex = (int)LanguageCode.koreana;
                break;
            case SystemLanguage.English:
                languageIndex = (int)LanguageCode.english;
                break;
            case SystemLanguage.ChineseSimplified:
                languageIndex = (int)LanguageCode.schinese;
                break;
            case SystemLanguage.ChineseTraditional:
                languageIndex = (int)LanguageCode.tchinese;
                break;
            case SystemLanguage.Japanese:
                languageIndex = (int)LanguageCode.japanese;
                break;
            // 어떠한 언어도 매칭되지 않으면 공통어로 많이 쓰는 영어로 설정
            default:
                languageIndex = (int)LanguageCode.english;
                break;
        }
        PlayerPrefs.SetInt(languageSetting, languageIndex);
    }

    // 설정에 맞는 언어 파일을 읽어들여 localizedText 딕셔너리에 정리
    // >> 언제든 효율적으로 찾을 수 있도록
    public void LoadLanguage()
    {
        string path = Path.Combine(Application.streamingAssetsPath, fileName);
        string json = File.ReadAllText(path);
        LocalizationFile file = JsonUtility.FromJson<LocalizationFile>(json);

        localizedText = new Dictionary<string, LocalizedValue>();
        foreach (var item in file.items)
        {
            localizedText[item.key] = item.value;
        }
    }

    // 해당 언어 설정으로 번역된 문자열 값을 가져오되 실패 시 실패했다고 텍스트 알림 >> 추후 번역 실패가 뜬다면 제보받은 부분에 쉽게 접근할 수 있음
    public string GetText(string key)
    {
        if(localizedText.TryGetValue(key, out var value))
        {
            return languageIndex switch
            {
                0 => value.ko,
                1 => value.en,
                2 => value.zh_CN,
                3 => value.zh_TW,
                4 => value.jp,
                _ => failText
            };
        }
        return failText;
    }

    // 현재 언어에 맞는 폰트 반환
    public void GetFont(TMP_Text uiText)
    {
        TMP_FontAsset fontNext = null;
        switch (languageIndex)
        {
            case (int)LanguageCode.koreana:
            case (int)LanguageCode.english:
            case (int)LanguageCode.japanese:
                fontNext = font_KE;
                break;
            case (int)LanguageCode.schinese:
                // 글자 아웃라인 색을 변경하기 위해 머티리얼 복제 후 색상 변경
                Material newMat_sc = new Material(uiText.fontSharedMaterial);
                uiText.fontMaterial = newMat_sc;
                uiText.fontMaterial.SetColor(ShaderUtilities.ID_OutlineColor, uiText.color);
                fontNext = font_zh_CN;
                break;
            case (int)LanguageCode.tchinese:
                // 글자 아웃라인 색을 변경하기 위해 머티리얼 복제 후 색상 변경
                Material newMat_tc = new Material(uiText.fontSharedMaterial);
                uiText.fontMaterial = newMat_tc;
                uiText.fontMaterial.SetColor(ShaderUtilities.ID_OutlineColor, uiText.color);
                fontNext = font_zh_TW;
                break;
            default:
                fontNext = font_KE;
                break;
        }
        uiText.font = fontNext;
        // 폰트 변경 후 메시 업데이트로 다시 로딩
        uiText.ForceMeshUpdate();
    }

    #endregion
}

 

 

3. Localization.json + 번역

해당 json 파일은 Assets\StreamingAssets 경로에 위치

 

key 하나에 언어 별 대응이 가능하여 새로운 항목/언어에 대해 추가/관리가 편하기에 해당 형태로 작성

 

AI 번역 교차 검증, 지인 검수를 통해 번역

AI의 번역 정확도가 매우 높아 검수를 통해 오역이 검출되지는 않음

 

4. LocalizationKeys

카테고리, 화면 내 텍스트를 각각을 지칭하는 key로 enum을 나누어 분류
LocalizationManager의 텍스트 반환 메서드(GetText)에서 어떤 문자열을 반환할지 지시

 

5. LocalizeKeySelectorDrawer

커스텀 에디터로 첫 드롭다운 선택 시 다음 드롭다운의 항목 리스트가 바뀌게끔 구조 생성

LocalizationKeys의 LocalizeCategory의 큰 범주를 고르면, 그 아래 세부 항목이 출현하게끔 하여 인스펙터 할당 작업 효율 상승

다음에 더 복잡한 게임에 현지화 작업을 할 일이 있다면 카테고리를 더 세분화할 예정

// 드롭다운에서 enum을 교체하여 로컬라이징 항목을 세분화(작업 효율성 증대)를 위한 커스텀 에디터

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System;

[CustomPropertyDrawer(typeof(LocalizeKeySelector))]
public class LocalizeKeySelectorDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var categoryProp = property.FindPropertyRelative("category");
        var keyProp = property.FindPropertyRelative("key");

        EditorGUI.BeginProperty(position, label, property);

        // 카테고리 선택
        Rect categoryRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.PropertyField(categoryRect, categoryProp);

        // 카테고리에 따라 enum 타입 결정
        Type enumType = null;
        switch ((LocalizeCategory)categoryProp.enumValueIndex)
        {
            case LocalizeCategory.Title: enumType = typeof(Title_Keys); break;
            case LocalizeCategory.Lobby: enumType = typeof(Lobby_Keys); break;
            case LocalizeCategory.Setting: enumType = typeof(Setting_Keys); break;
            case LocalizeCategory.WaitingRoom: enumType = typeof(WaitingRoom_Keys); break;
            case LocalizeCategory.Tutorial: enumType = typeof(Tutorial_Keys); break;
            case LocalizeCategory.Game: enumType = typeof(InGame_Keys); break;
            case LocalizeCategory.Map: enumType = typeof(MapName_Keys); break;
            case LocalizeCategory.Weapon: enumType = typeof(Weapon_Keys); break;
            case LocalizeCategory.Item: enumType = typeof(Item_Keys); break;
            case LocalizeCategory.Paintables: enumType = typeof(Paintable_Keys); break;
            case LocalizeCategory.Customize: enumType = typeof(Customize_keys); break;
            // 큰 카테고리 enum 추가 시 enum LocalizeCategory에 항목을 추가한 뒤, 여기에 추가
        }

        // enumType에 따라 그에 해당하는 enum 항목들을 드롭다운으로 생성
        if (enumType != null)
        {
            Array values = Enum.GetValues(enumType);
            string[] names = Enum.GetNames(enumType);
            int index = Array.IndexOf(names, keyProp.stringValue);
            if (index < 0) index = 0;

            Rect keyRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + 2, position.width, EditorGUIUtility.singleLineHeight);
            int newIndex = EditorGUI.Popup(keyRect, "Key", index, names);
            keyProp.stringValue = names[newIndex];
        }

        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight * 2 + 4;
    }
}
#endif

 

 

6. LocalizedText

런타임 중 변하지 않는 텍스트를 언어 옵션에 맞게 바꿔주는 스크립트

작업 팁: 씬 하이어라키에서 t:tmp_text 를 검색. 이 중 고정 텍스트에만 해당 스크립트 부착 및 드롭다운 설정


아래 코드에서 텍스트 머티리얼의 셰이더를 변경하는 부분들이 있는데, 이는 게임 중 오버레이가 필요한 텍스트들이 있었기에 조치한 내용이므로 공부용으로 보는 분은 해당 내용 제외할 것

using TMPro;
using UnityEngine;

[RequireComponent(typeof(TextMeshProUGUI))]
public class LocalizedText : MonoBehaviour
{
    // JSON에서 사용할 키 >> 인스펙터에서 드롭다운 할당 필요
    [SerializeField] LocalizeKeySelector localizeKeySelector;

    private TextMeshProUGUI uiText;

    Material newMat;
    Shader tmpShader;

    readonly string overlayShaderPath = "TextMeshPro/Distance Field Overlay",
                    nonOverlayShaderPath = "TextMeshPro/Distance Field";

    private void Awake()
    {
        uiText = GetComponent<TextMeshProUGUI>();
        // 머티리얼을 공유본에서 복사
        newMat = new Material(uiText.fontSharedMaterial);
        // 구조물 이름 표시는 Distance Field Overlay 셰이더가 필요
        // 다만, 이전에 작업하다 실수로 모든 텍스트 셰이더를 덮어 씌웠기에 원복용으로 else 구문 투입
        string tmpShaderPath = null;
        if (localizeKeySelector.category == LocalizeCategory.Paintables)
        {
            tmpShaderPath = overlayShaderPath;
        }
        else
        {
            tmpShaderPath = nonOverlayShaderPath;
        }

        tmpShader = Shader.Find(tmpShaderPath);
        if (tmpShader != null)
        {
            newMat.shader = tmpShader;
        }
        else
        {
            Debug.LogWarning(tmpShaderPath + " 셰이더를 찾을 수 없습니다.");
        }

        uiText.fontMaterial = newMat;
    }

    // 언어 변경 시 자동으로 해당 설정으로 텍스트가 바뀌게끔 이벤트 등록/해제
    private void OnEnable()
    {
        LocalizationManager.OnLanguageChanged += UpdateText;
        // 활성화 때 언어 설정에 따라 출력 정보 변경
        UpdateText();
    }

    private void OnDisable()
    {
        LocalizationManager.OnLanguageChanged -= UpdateText;
    }

    // 언어 설정에 따른 텍스트 표시 변경
    public void UpdateText()
    {
        if (LocalizationManager.instance != null && !string.IsNullOrEmpty(localizeKeySelector.key.ToString()))
        {
            // 언어에 따라 대응하는 폰트 변경
            LocalizationManager.instance.GetFont(uiText);
            // 폰트 변경 후
            // 머티리얼을 공유본에서 복사
            newMat = new Material(uiText.fontSharedMaterial);
            // 머티리얼의 셰이더를 맞는 것으로 변경
            newMat.shader = tmpShader;
            uiText.fontMaterial = newMat;
            // 중국어일 경우, 머티리얼 복사본(독립됨)의 아웃라인 색상을 폰트 색상과 같게 변경
            if (LocalizationManager.instance.languageIndex == (int)LanguageCode.schinese || LocalizationManager.instance.languageIndex == (int)LanguageCode.tchinese)
            {
                uiText.fontMaterial.SetColor(ShaderUtilities.ID_OutlineColor, uiText.color);
            }
            // 텍스트 변경
            uiText.text = LocalizationManager.instance.GetText(localizeKeySelector.key.ToString());
            // 텍스트 다시 랜더링
            uiText.ForceMeshUpdate();
        }
    }
}

 

7. LocalizedDropDown

드롭다운 각 항목에 번역이 필요한 경우 사용

설정한 언어에 따라 드롭다운 항목 문자열 변경 예시

 

using TMPro;
using UnityEngine;

// 드롭다운 번역 사용법
// 드롭다운 아이템들을 각 언어에 맞춰 번역만 할 때는 해당 스크립트를 드롭다운이 있는 오브젝트에 부착
// 인스펙터에서 어떤 내용을 표시할지 할당해주기
// 기존에 없던 내용 추가 시, LocalizationKey.cs, Localization.json 에 기입

// 아래 경우 해당 스크립트를 상속하여 기능을 추가하면 확장 가능
// 1. 초기 value 선택이 필요 >> SetEnableItem()을 오버라이드하여 초기 선택과 관련한 내용 작성
// 2. 드롭다운 선택으로 value가 바뀌었을 때 이벤트 필요 >> OnDropdownValueChanged()을 오버라이드하여 base.OnDropdownValueChanged();을 포함. 

[RequireComponent(typeof(TMP_Dropdown))]
public class LocalizedDropDown : MonoBehaviour
{
    // JSON에서 사용할 키들 >> 인스펙터에서 드롭다운 할당 필요
    [SerializeField] protected LocalizeDropDownKeysSelector dropDownSelector;

    protected TMP_Dropdown dropDown;

    private void Awake()
    {
        // 드롭다운 값이 변경될 때마다 실제 리스트 항목의 폰트를 맞춰주게끔 이벤트 등록
        if (TryGetComponent(out dropDown))
            dropDown.onValueChanged.AddListener(OnDropdownValueChanged);
    }

    // 언어 변경 시 자동으로 해당 설정으로 텍스트가 바뀌게끔 이벤트 등록/해제
    private void OnEnable()
    {
        LocalizationManager.OnLanguageChanged += UpdateDropdown;
        // 활성화 때 언어 설정에 따라 출력 정보 변경
        UpdateDropdown();
        SetEnableItem();
    }

    private void OnDisable()
    {
        LocalizationManager.OnLanguageChanged -= UpdateDropdown;
    }

    private void OnDestroy()
    {
        dropDown.onValueChanged.RemoveListener(OnDropdownValueChanged);
    }

    // 언어 설정에 따른 텍스트 표시 변경
    protected virtual void UpdateDropdown()
    {
        if (LocalizationManager.instance == null)
            return;

        // 언어에 따라 대응하는 폰트 변경
        LocalizationManager.instance.GetFont(dropDown.itemText);

        // 기존 드롭다운 옵션 클리어
        dropDown.options.Clear();

        // 언어에 해당하는 텍스트로 항목들을 변경
        for (int i = 0; i < dropDownSelector.categories.Length; i++)
        {
            string keyTmp = dropDownSelector.categories[i].key.ToString();
            if (string.IsNullOrEmpty(keyTmp))
                continue;
            string localizedItem = LocalizationManager.instance.GetText(keyTmp);
            dropDown.options.Add(new TMP_Dropdown.OptionData(localizedItem));
        }

        // 바꾼 내용대로 드롭다운 리로드
        dropDown.RefreshShownValue();
    }

    // 각 드롭다운 별 값이 바뀌었을 때 수행할 내용.
    // 기본형은 공통으로 들어갈 내용만 담겨 있음
    protected virtual void OnDropdownValueChanged(int index)
    {
        // 드롭다운 열림 시점에 리스트 항목들의 폰트를 강제 적용
        var texts = dropDown.GetComponentsInChildren<TextMeshProUGUI>(true);
        foreach (var t in texts)
        {
            t.font = dropDown.itemText.font;
        }
    }

    // 각 드롭다운 별 초기 항목 선택 관련 추상 메서드
    protected virtual void SetEnableItem(){}
}

 

위의 코드를 상속한 드롭다운 항목 선택 시 / 초기 옵션 세팅 예시

public class DropDown_LocalizationSetting : LocalizedDropDown
{
    protected override void OnDropdownValueChanged(int index)
    {
        base.OnDropdownValueChanged(index);
        // 선택한 항목을 LocalizationManager에 반영
        LocalizationManager.instance.SetLanguage(index);
    }

    protected override void SetEnableItem()
    {
        // 언어 옵션에 따라 초기 항목 선택 변경
        int languageIndex = LocalizationManager.instance.languageIndex;

        if(dropDown != null)
        {
            if(languageIndex <dropDown.options.Count)
                dropDown.value = LocalizationManager.instance.languageIndex;
        }
    }
}

 

8. 주의사항 및 세부작업

다른 언어로 바꿨을 때 같은 뜻이라도 문장 길이가 달라짐

이에 따라 텍스트가 UI를 삐져나옴

 

특히, 영어가 같은 뜻이라도 길어지는 경우가 많았음

 

(1) 텍스트 박스 크기 조정 = 텍스트를 표시할 영역에 맞춤

Scene 뷰에서 시각적으로 판단
보통은 Rect Transform 선에서 크기 결정 가능

 

TMP_Text의 Margins를 통해 영역에서 얼만큼 마진을 둘지 추가 설정 가능

 

(2) Auto Size + 옵션 Min/Max 조절을 통해 주변 UI와 글자 크기를 맞추어 이질감을 최소화

 

저작자표시 비영리 동일조건 (새창열림)

'기타' 카테고리의 다른 글

시프트+딜리트로 실수로 파일을 삭제했을 때 무료 복구 방법  (7) 2025.03.29
티스토리 다크 모드 무료 스킨 추천 및 적용  (0) 2025.03.02
C/C++ 비전공자의 눈으로 보는 포인터 (Pointer)  (2) 2025.03.02
C) 하노이의 탑 실행창에서 게임으로 즐기기 (exe, 소스 코드 첨부)  (0) 2025.03.01
gif 배너 만들 때 사용한 툴 정리  (0) 2024.03.14
'기타' 카테고리의 다른 글
  • 시프트+딜리트로 실수로 파일을 삭제했을 때 무료 복구 방법
  • 티스토리 다크 모드 무료 스킨 추천 및 적용
  • C/C++ 비전공자의 눈으로 보는 포인터 (Pointer)
  • C) 하노이의 탑 실행창에서 게임으로 즐기기 (exe, 소스 코드 첨부)
ybbro
ybbro
대부분의 포스팅은 pc에서 작성되었습니다. 모바일에서 볼 때 설명이 잘리면 데스크탑 모드를 사용해보길 바랍니다.
  • ybbro
    어떻게든 굴리는 게임 공방
    ybbro
  • 전체
    오늘
    어제
    • 전체
      • 스파르타코딩클럽_Unity개발과정
      • Unity 2D
        • 카드게임
        • 플랫포머 게임
        • 뱀서라이크
      • Unity 3D
        • 닷지
        • 유니티 짱
        • 디펜스 게임
        • Inkoid
      • Unity 에러 노트
      • 기능 구현 방법 정리
      • 셰이더 그래프
        • 2D
        • 3D
      • 프로그래머스
      • 자료구조
      • 기타
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스파인
    hello
    마스크
    갤럭시 S24
    64비트
    텍스트매시프로
    UI
    삭제
    대시
    세이브
    직렬화
    잔상
    룰렛
    unity
    유니티 애니메이터 파라미터 초기화
    앱이 휴대전화와 호환되지 않아 설치되지 않았습니다
    무료스킨
    유니티
    sprite mask
    다크모드
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
ybbro
유니티 게임 Localization (현지화) 작업
상단으로

티스토리툴바