본문 바로가기
디지털노마드

챗GPT 게임개발82:Unity 스크립터블 오브젝트로 다국어 폰트 관리 시스템 최적화하기

by 인텔리노마드라이프 2025. 2. 3.
728x90

안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.

 

이번 시간에는 **스크립터블 오브젝트(ScriptableObject)**를 활용해 다국어 폰트 관리 시스템을 효율적으로 개선하는 방법을 소개합니다. 기존 코드의 문제점을 분석하고, 스크립터블 오브젝트를 도입해 유지보수성을 높이는 과정을 단계별로 설명드리겠습니다.


신개념 메모리 게임의 탄생. 외워라! 창고.

2024.11.14 - [분류 전체보기] - [외워라!창고] 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다!

 

[외워라!창고] 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다!

안녕하세요, 인텔리원스튜디오(IntelliOneStudio)에서 흥미진진한 소식을 가지고 왔어요! 저희가 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다! 이 게임은 챗GPT의 놀라운 AI 기능을

intellinomadlife.tistory.com

 

 

창고에 물건을 보관하면 더이상 보여주지 않고, 오로지 당신의 기억력으로 찾아야해요.

저희가 챗GPT를 활용해서 개발한 첫 번째 게임을 여러분께 소개합니다! 이 게임은 챗GPT의 놀라운 AI 기능을 활용해 개발했어요. 즐거움이 가득한 이번 게임은, 챗GPT를 활용해서 누구든지 게임을 재미있게 만들 수 있다는 것을 보여줄 거에요.

 

* APP Store 에서 다운로드 

https://apps.apple.com/kr/app/%EB%86%8D%EB%B6%80%EC%9D%98-%EA%BF%88/id6479183930

 

‎농부의 꿈

‎오래된 전설이 숨겨져 있는 [농부의 꿈]목장 한구석에서 ‘비밀의 문'과 '마법 책'이 발견되었어요. [변신하는 동물들] 병아리가 합쳐져 닭이 되고, 닭이 합쳐져 고슴도치로 변신하며, 점점 더

apps.apple.com

 

*Google Play 에서 다운로드

https://play.google.com/store/apps/details?id=com.intellione.farmersfirstdream&pcampaignid=web_share 

 

농부의 꿈 - Google Play 앱

평화로운 목장에서 신나는 동물 합치기 무료게임 (바람, 뚫어뻥, 밧줄, 무중력 등 매직 아이템 활용해 병아리를 젖소로 키워보세요.)

play.google.com


 

1. 기존 코드의 문제점 분석

제공된 AvatarDefault 클래스는 다양한 언어별 폰트를 관리하기 위해 각 언어마다 별도의 필드를 직렬화(Serialize)하고 있습니다. 이 방식은 다음과 같은 문제점을 가집니다:

using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.UI;

namespace WarehouseDeliveryQuest.UI
{
    public class AvatarDefault : MonoBehaviour
    {
        // 로컬라이즈 텍스트 UI 요소
        [SerializeField] private TextMeshProUGUI localizedText;

        // 로컬라이즈된 텍스트 필드
        [SerializeField] private LocalizedString localizedTextString;

        // 폰트 설정을 위한 변수
        [SerializeField] private TMP_FontAsset koreanFont;
        [SerializeField] private TMP_FontAsset englishFont;
        [SerializeField] private TMP_FontAsset japaneseFont;
        [SerializeField] private TMP_FontAsset vietnameseFont;
        [SerializeField] private TMP_FontAsset spanishFont;
        [SerializeField] private TMP_FontAsset frenchFont;
        [SerializeField] private TMP_FontAsset indonesianFont;

        private void Start()
        {
            // 로컬라이즈된 텍스트 설정 및 폰트 적용
            localizedTextString.GetLocalizedStringAsync().Completed += handle =>
            {
                if (localizedText != null)
                {
                    localizedText.text = handle.Result;
                    ApplyLocalizedFont(localizedText);
                }
            };

            // 로케일 변경 이벤트 구독
            LocalizationSettings.SelectedLocaleChanged += OnLocaleChanged;

        }

        // 로케일 변경 시 호출되는 메서드
        private void OnLocaleChanged(Locale newLocale)
        {
            // 로케일이 변경되면 텍스트와 폰트를 업데이트
            localizedTextString.GetLocalizedStringAsync().Completed += handle =>
            {
                if (localizedText != null)
                {
                    localizedText.text = handle.Result;
                    ApplyLocalizedFont(localizedText);
                }
            };
        }

        // 텍스트에 로컬라이즈된 폰트를 적용하는 메서드
        private void ApplyLocalizedFont(TextMeshProUGUI textElement)
        {
            TMP_FontAsset selectedFont = englishFont; // Default to English font
            string currentLocale = LocalizationSettings.SelectedLocale.Identifier.Code;

            switch (currentLocale)
            {
                case "ko":
                    selectedFont = koreanFont;
                    break;
                case "ja":
                    selectedFont = japaneseFont;
                    break;
                case "vi":
                    selectedFont = vietnameseFont;
                    break;
                case "es":
                    selectedFont = spanishFont;
                    break;
                case "fr":
                    selectedFont = frenchFont;
                    break;
                case "id":
                    selectedFont = indonesianFont;
                    break;
                case "en":
                default:
                    selectedFont = englishFont;
                    break;
            }

            // 폰트가 설정되면 적용
            if (selectedFont != null)
            {
                textElement.font = selectedFont;
            }
            else
            {
                // Debug.LogWarning("폰트가 설정되지 않았습니다.");
            }
        }
    }
}
  1. 확장성 부족:
    • 새로운 언어를 추가할 때마다 필드를 계속 추가해야 합니다.
    • koreanFont, englishFont, japaneseFont 등 각 언어마다 독립적인 변수가 필요합니다.
  2. 유지보수 어려움:
    • 언어가 늘어날수록 인스펙터(Inspector)가 복잡해집니다.
    • 코드 수정 없이 데이터만 변경하기 어렵습니다.
  3. 중복 코드 발생:
    • ApplyLocalizedFont 메서드에서 언어별 폰트 매핑을 수동으로 관리합니다.

2. 스크립터블 오브젝트 도입

이 문제를 해결하기 위해 스크립터블 오브젝트를 사용해 언어와 폰트를 매핑하는 데이터 컨테이너를 생성합니다.

단계 1: 폰트 데이터 클래스 생성

using UnityEngine;
using TMPro;

[System.Serializable]
public class LanguageFontPair
{
    public string localeCode; // 언어 코드 (예: "ko", "en")
    public TMP_FontAsset fontAsset; // 해당 언어의 폰트
}

[CreateAssetMenu(fileName = "FontData", menuName = "Localization/Font Data")]
public class FontData : ScriptableObject
{
    public LanguageFontPair[] fontMappings; // 언어별 폰트 매핑 배열
}

 

  • LanguageFontPair 클래스: 언어 코드와 폰트 에셋을 연결합니다.
  • FontData 클래스: 모든 언어 매핑을 저장하는 스크립터블 오브젝트입니다.

단계 2: 스크립터블 오브젝트 생성

  1. Unity 에디터에서 우클릭 → Create → Localization → Font Data를 선택합니다.
  2. 인스펙터에서 언어 코드와 폰트를 매핑합니다.
    • 예: ko → 한국어 폰트, en → 영어 폰트 등

3. 개선된 코드 구현

스크립터블 오브젝트를 활용해 기존 코드를 리팩토링합니다.

using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;

namespace WarehouseDeliveryQuest.UI
{
    public class AvatarDefault : MonoBehaviour
    {
        [SerializeField] private TextMeshProUGUI localizedText;
        [SerializeField] private LocalizedString localizedTextString;
        [SerializeField] private FontData fontData; // 스크립터블 오브젝트 참조

        private void Start()
        {
            UpdateLocalizedText();
            LocalizationSettings.SelectedLocaleChanged += OnLocaleChanged;
        }

        private void OnLocaleChanged(Locale newLocale)
        {
            UpdateLocalizedText();
        }

        private void UpdateLocalizedText()
        {
            localizedTextString.GetLocalizedStringAsync().Completed += handle =>
            {
                if (localizedText != null)
                {
                    localizedText.text = handle.Result;
                    ApplyLocalizedFont(localizedText);
                }
            };
        }

        private void ApplyLocalizedFont(TextMeshProUGUI textElement)
        {
            string currentLocale = LocalizationSettings.SelectedLocale.Identifier.Code;
            TMP_FontAsset selectedFont = null;

            // 스크립터블 오브젝트에서 폰트 검색
            foreach (var mapping in fontData.fontMappings)
            {
                if (mapping.localeCode == currentLocale)
                {
                    selectedFont = mapping.fontAsset;
                    break;
                }
            }

            // 기본 폰트 설정 (예: 영어)
            if (selectedFont == null)
            {
                foreach (var mapping in fontData.fontMappings)
                {
                    if (mapping.localeCode == "en")
                    {
                        selectedFont = mapping.fontAsset;
                        break;
                    }
                }
            }

            textElement.font = selectedFont;
        }

        private void OnDestroy()
        {
            LocalizationSettings.SelectedLocaleChanged -= OnLocaleChanged;
        }
    }
}

 

4. 개선된 시스템의 장점

  1. 확장성 향상:
    • 새로운 언어를 추가할 때 코드를 수정할 필요 없이 스크립터블 오브젝트만 업데이트하면 됩니다.
  2. 유지보수 용이:
    • 모든 폰트 매핑이 한 곳(FontData)에서 관리됩니다.
    • 인스펙터가 깔끔해지고 데이터 수정이 간편합니다.
  3. 재사용성 증가:
    • FontData 스크립터블 오브젝트를 다른 씬이나 프로젝트에서 재사용할 수 있습니다.

5. 실제 적용 방법

  1. 스크립터블 오브젝트 할당:
    • AvatarDefault 컴포넌트의 FontData 필드에 생성한 FontData 에셋을 드래그 앤 드롭합니다.
  2. 언어 추가:
    • FontData 인스펙터에서 새로운 언어 코드와 폰트를 추가합니다.
  3. 실행 테스트:
    • Unity 에디터에서 로케일을 변경하며 폰트가 정상적으로 적용되는지 확인합니다.

6. 추가 개선 방안

  1. 자동 매핑 검색:
    • Dictionary<string, TMP_FontAsset>을 사용해 검색 성능을 향상시킬 수 있습니다.
  2. 에디터 확장:
    • 커스텀 에디터를 만들어 언어 코드 입력을 자동화할 수 있습니다.
  3. 폴백 시스템:
    • 특정 언어 폰트가 없을 경우 기본 폰트를 지정하는 로직을 추가합니다.

마무리

스크립터블 오브젝트를 활용하면 다국어 폰트 관리 시스템을 더 효율적으로 구축할 수 있습니다. 이 기법은 폰트뿐만 아니라 사운드, 이미지, 밸런스 데이터 등 다양한 리소스 관리에도 적용할 수 있습니다.

유니티의 강력한 데이터 관리 도구를 활용해 프로젝트의 유지보수성을 높여보세요!

 

지금까지 인텔리원스튜디오(IntelliOneStudio)였습니다.
감사합니다.

728x90