본문 바로가기

내일 배움 캠프/TIL

[내일 배움 캠프] 54일차 TIL

[Addressables 기반 ResourceManager 설계]

리소를 효율적으로 관리하려면 로딩, 인스턴스화, 파괴, 풀링, 비동기 처리를 하나의 체계로 묶을 필요가 있다.

Addressables를 기반으로 한 ResourceManager 설계 방식과 Addressables 사용 시 발생할 수 있는 .sprite 키 처리 문제에 대한 해결 방법을 소개한다.

 

목표

    ● Addressables 기반 리소스 로딩/캐싱 구조 구현

    ● 풀링 및 일반 인스턴스화를 동시에 지원

    ● .sprite 키로 Sprite 리소스 로드 시 발생하는 문제 해결

    ● 유지보수 가능한 코드 구조 제공

 

구조 설계 의도

    ● 의존성 분리: Addressables API는 내부에서만 사용되며 외부에서는 추상화된 인터페이스로 접근

    ● 중앙 집중화: 모든 리소스 접근, 생성, 해제, 캐싱을 한 곳에서 통제

    ● 성능 최적화: 풀링 시스템과 결합하여 메모리 할당/해제 최소화

    ● 확장성 고려: T 제네릭 기반 로딩으로 다양한 Unity Object 처리 가능

 

.sprite 키 처리 문제

    ● 문제 상황

        ○ Unity의 Addressable로 Sprite를 로드할 때 .sprite 키를 사용하면 종종 Texture2D로 인식되거나 SpriteAtlas 전체로 로드되는 문제가 발생함

LoadAsync<Sprite>("slime.sprite", sprite => { ... }); 
// 예상: Sprite 로드 → 실제: 실패하거나 Texture2D로 인식됨

 

    ● 해결 방법

        ○ SpriteAtlas 키 형식 맞추기

        ○ Addressables는 SpriteAtlas 내부의 Sprite를 다음과 같은 형식으로 로드해야 한다

        ○ 즉, 슬라임 이름은 SpriteAtlas 내부의 Sprite 이름이다

key: slime.sprite[슬라임이름]

 

    ● 코드 내 처리

public void LoadAsync<T>(string key, Action<T> callback = null) where T : UnityEngine.Object
{
    string loadKey = key;

    // Sprite 키 변형 처리
    if (key.Contains(".sprite"))
    {
        loadKey = $"{key}[{key.Replace(".sprite", "")}]";
    }

    var asyncOperation = Addressables.LoadAssetAsync<T>(loadKey);
    asyncOperation.Completed += (op) =>
    {
        if (_resources.TryGetValue(key, out Object cached))
        {
            callback?.Invoke(cached as T);
            return;
        }

        // Texture2D로 로드된 경우 수동 Sprite 생성
        if (typeof(T) == typeof(Sprite) && op.Result is Texture2D tex)
        {
            var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
            _resources.Add(key, sprite);
            callback?.Invoke(sprite as T);
        }
        else
        {
            _resources.Add(key, op.Result);
            callback?.Invoke(op.Result);
        }
    };
}