프로젝트 일지/Unity

[Unity/TIL] Addressable 연구

톰마토 2025. 4. 8. 23:43

이번 프로젝트에서는 Addressable을 사용할 것이다. 빌드 시 Resources.Load를 사용하는 것보다 무조건 빌드 용량에 이점이 있기 때문이다. 그외에도 다음과 같은 장점들이 있다. 

  • 서버와 Addressable을 함께 사용하면 빌드 후에 원격에서 리소스를 수정하는 것이 가능해진다. 클라 재배포 없이 패치가 가능한 것이 짱 큰 이점이다. (우리는 서버를 사용하지 않을 수도 있지만)
  • 비동기 로딩이 가능하다. 프레임 드랍 없이 자연스러운 로딩화면을 구현할 수 있다. 
  • 내부적으로 에셋 번들을 별도로 관리해준다.
  • 리소스마다 라벨, 키 지정 가능해서 리소스 그룹 관리 편리하다. 
Addressable 이해를 도와주신(사실 떠먹여주신) 짱동료 송석호님께 왕큰감사를 드림미댜... (●'◡'●)
전반적인 프레임워크 구조를 잡는 것에 도움을 주셔서 넘나 감사합니다!!!!!!!!

 

비동기 함수를 사용하기 때문에 신경써야 하는 부분이 조금 있지만, .PercentComplete, .IsDone, .Completed 로 상태 추적이 가능하다. 그래서 비동기 Load 함수를 아래와 같이 만들어서, Completed에 완료 후에 실행할 onComplete 액션을 연결해줬다. 

// 사용할 때 key로 검색해서 로드하고, 로드된 후에 실행할 함수를 onComplete에 넣어주면 된다.

private readonly Dictionary<string, List<string>> keys = new();
private readonly Dictionary<string, AsyncOperationHandle> operations = new();

public AsyncOperationHandle LoadAssetAsync<T>(string key, Action<T> onComplete = null) where T : Object
{
    if (operations.TryGetValue(key, out var operation))
    {
        onComplete?.Invoke(operation.Result as T);
        return operation;
    }

    operation = Addressables.LoadAssetAsync<T>(key); // Addressable의 로드 함수
    operation.Completed += operation => onComplete?.Invoke(operation.Result as T);
    operations.Add(key, operation);
    return operation;
}

Addressables로 로드하고 나면 나오는 AsyncOperationHandle는 핸들ID, 레퍼런스 카운트, 결과 객체 등의 여러 데이터를 담고 있는 구조체이다. 이 핸들이 참조하는 리소스는 자동으로 Release되지 않는다. 따라서 직접 해제시켜주기 위해 핸들을 operations라는 Dictionary에 넣어주는 것이다. 

 

그래서 씬을 로드할 때 해당 씬에서 필요한 리소스를 label로 묶여있는 그룹으로 한 번에 로드하고, 씬이 전환될 때 이전 씬에서 사용된 리소스들을 Release할 수 있도록 만들 생각이다. 그룹으로 로드하는 건 다음 글에 써야지!!! 

 

그리고 실질적으로 직접 사용하게 될 함수는 Instantiate이다. Pool에 있다면 꺼내서 쓰고, 없다면 새로 비동기 로드해서 사용하는 함수를 만든 것이다. 이때 유니티에서 제공하는 Instantiate처럼 새로 생성한 게임오브젝트로 무언가를 하고 싶다면 onComplete에서 해야 한다. 

public void Instantiate(string key, Action<GameObject> onComplete = null)
{
    GameObject gameObject = Managers.Pool.Get(key);
    if (gameObject != null)
    {
        onComplete?.Invoke(gameObject);
        return;
    }

    LoadAssetAsync<GameObject>(key, original => onComplete?.Invoke(Instantiate(original)));
}

 

사용 모습

오늘 직접 사용해봤다. 루키스님의 UI 자동화 구조를 레퍼런스로 염두에 두고 있는데, 루키스님의 강의에서는 Addressable을 사용하지 않았기 때문에 수정이 필요했다. 

적용해본 코드