안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
이번 시간에는 **스크립터블 오브젝트(ScriptableObject)**를 활용해 다국어 폰트 관리 시스템을 효율적으로 개선하는 방법을 소개합니다. 기존 코드의 문제점을 분석하고, 스크립터블 오브젝트를 도입해 유지보수성을 높이는 과정을 단계별로 설명드리겠습니다.
2024.11.14 - [분류 전체보기] - [외워라!창고] 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다!
[외워라!창고] 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다!
안녕하세요, 인텔리원스튜디오(IntelliOneStudio)에서 흥미진진한 소식을 가지고 왔어요! 저희가 챗GPT를 활용해서 개발한 두 번째 게임을 여러분께 소개합니다! 이 게임은 챗GPT의 놀라운 AI 기능을
intellinomadlife.tistory.com
창고에 물건을 보관하면 더이상 보여주지 않고, 오로지 당신의 기억력으로 찾아야해요.
날이 갈수록 늘어나는 상품들과 주문에도 정확하고 빠르게 물건을 찾아 배송해야해요.
과연 당신은 며칠까지 버틸수 있을까요?
당신의 기억력을 시험해봐요. 지금 다운로드하세요.
[아이폰 앱스토어 다운로드]
https://apps.apple.com/kr/app/%EC%99%B8%EC%9B%8C%EB%9D%BC%EC%B0%BD%EA%B3%A0/id6737766088
외워라창고
환영합니다. 우리 창고는 매일 새롭게 들어오는 상품을 각기 다른 각기 다른 상자에 보관해요. 주문이 들어오면 그 상품들을 찾아 포장하고, 정확한 주소로 배송하는 것이 여러분의 임무입니
apps.apple.com
[구글 플레이 다운로드]
https://play.google.com/store/apps/details?id=com.intellione.warehousedelivery
외워라 창고 - Google Play 앱
창고의 기억왕: 물건 찾기의 달인이 되어라.
play.google.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("폰트가 설정되지 않았습니다.");
}
}
}
}
- 확장성 부족:
- 새로운 언어를 추가할 때마다 필드를 계속 추가해야 합니다.
- koreanFont, englishFont, japaneseFont 등 각 언어마다 독립적인 변수가 필요합니다.
- 유지보수 어려움:
- 언어가 늘어날수록 인스펙터(Inspector)가 복잡해집니다.
- 코드 수정 없이 데이터만 변경하기 어렵습니다.
- 중복 코드 발생:
- 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: 스크립터블 오브젝트 생성
- Unity 에디터에서 우클릭 → Create → Localization → Font Data를 선택합니다.
- 인스펙터에서 언어 코드와 폰트를 매핑합니다.
- 예: 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. 개선된 시스템의 장점
- 확장성 향상:
- 새로운 언어를 추가할 때 코드를 수정할 필요 없이 스크립터블 오브젝트만 업데이트하면 됩니다.
- 유지보수 용이:
- 모든 폰트 매핑이 한 곳(FontData)에서 관리됩니다.
- 인스펙터가 깔끔해지고 데이터 수정이 간편합니다.
- 재사용성 증가:
- FontData 스크립터블 오브젝트를 다른 씬이나 프로젝트에서 재사용할 수 있습니다.
5. 실제 적용 방법
- 스크립터블 오브젝트 할당:
- AvatarDefault 컴포넌트의 FontData 필드에 생성한 FontData 에셋을 드래그 앤 드롭합니다.
- 언어 추가:
- FontData 인스펙터에서 새로운 언어 코드와 폰트를 추가합니다.
- 실행 테스트:
- Unity 에디터에서 로케일을 변경하며 폰트가 정상적으로 적용되는지 확인합니다.
6. 추가 개선 방안
- 자동 매핑 검색:
- Dictionary<string, TMP_FontAsset>을 사용해 검색 성능을 향상시킬 수 있습니다.
- 에디터 확장:
- 커스텀 에디터를 만들어 언어 코드 입력을 자동화할 수 있습니다.
- 폴백 시스템:
- 특정 언어 폰트가 없을 경우 기본 폰트를 지정하는 로직을 추가합니다.
마무리
스크립터블 오브젝트를 활용하면 다국어 폰트 관리 시스템을 더 효율적으로 구축할 수 있습니다. 이 기법은 폰트뿐만 아니라 사운드, 이미지, 밸런스 데이터 등 다양한 리소스 관리에도 적용할 수 있습니다.
유니티의 강력한 데이터 관리 도구를 활용해 프로젝트의 유지보수성을 높여보세요!
지금까지 인텔리원스튜디오(IntelliOneStudio)였습니다.
감사합니다.
'디지털노마드' 카테고리의 다른 글
챗GPT 게임개발84:2025년 유니티 게임 개발 최신 트렌드: 차세대 기술로 경쟁력 확보하기 (2) | 2025.02.08 |
---|---|
챗GPT 게임개발83:유니티 개발자 필수 노하우: 효율성과 퀄리티를 높이는 5가지 팁 (1) | 2025.02.06 |
챗GPT 게임개발81: Cursor AI Editor 로 Unity 개발을 더 스마트하게 (3) | 2025.01.31 |
챗GPT 게임개발80: Unity에서 다양한 조이스틱 타입을 활용한 플레이어 컨트롤 구현하기 (6) | 2025.01.06 |
챗GPT 게임개발79: Cursor vs Windsurf vs Bolt.new — “최고의 AI 코드 에디터”를 찾아서 (1) | 2024.12.31 |