리소스 매니저(어드레서블)
리소스 매니저를 소개하기 전에, 제 모든 리소스는 어드레서블(리모트)로 등록되어 있습니다.
(초기 어드레서블을 다운로드하기 전에는 파일을 제외하고 있습니다.)
그러므로, 어드레서블 시스템을 사용하지 않으면 제 리소스 매니저를 사용할 수 없습니다.
리소스 매니저는 모든 리소스를 생성하고 관리하는 데 편의성을 제공하기 위한 것입니다.
또한, 풀링까지 자동으로 수행합니다.
먼저 어드레서블 매니저를 사용하여 에셋을 로드하는 방법을 소개하겠습니다.
private enum eAddressableType
{
Start,
DefaultIsolation,
Animation,
Audio,
Font,
Material,
Model,
Prefab,
Scenes,
ScriptableObjects,
End,
}
C#
복사
위처럼 어드레서블에 등록한 모든 타입들을 enum값에 담은 후, 아래 로직을 실행합니다.
설정된 리모트 파일에 어드레서블 에셋을 로드하는 방법입니다.
제 어드레서블 에셋은 AWS-S3에 등록되어 있습니다.
private readonly Dictionary<string, IResourceLocation> _addressableLocation =
new Dictionary<string, IResourceLocation>();
public async void InitResourceManager()
{
_addressableLocation.Clear();
for (var addressableType = eAddressableType.Start + 1;
addressableType < eAddressableType.End;
addressableType++)
{
var locationsHandle = Addressables.LoadResourceLocationsAsync(addressableType.ToString());
await locationsHandle.Task;
var locations = locationsHandle.Result;
foreach (var location in locations)
{
var primaryKey = location.PrimaryKey;
var split = primaryKey.Split('/');
primaryKey = split[^1];
var lastDotIndex = primaryKey.LastIndexOf('.');
if (lastDotIndex != -1)
{
primaryKey = primaryKey.Substring(0, lastDotIndex);
}
if (_addressableLocation.ContainsKey(primaryKey))
{
continue;
}
_addressableLocation.Add(primaryKey, location);
}
// Download all the assets associated with the current addressableType.
var downloadHandle = Addressables.DownloadDependenciesAsync(addressableType.ToString());
await downloadHandle.Task;
if (downloadHandle.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log($"Downloaded all dependencies for {addressableType}");
}
else
{
Debug.LogError($"Failed to download dependencies for {addressableType}");
}
}
}
C#
복사
public UniTask<T> LoadAssetAsync<T>(string assetName) where T : Object
{
if (_addressableLocation.ContainsKey(assetName) == false) return default;
return AddressablesManager.LoadAssetAsync<T>(_addressableLocation[assetName]);
}
public UniTask<SceneInstance> LoadSceneAsync(string sceneName, LoadSceneMode loadMode = LoadSceneMode.Single,
bool activateOnLoad = true)
{
if (_addressableLocation.ContainsKey(sceneName) == false)
{
Debug.Log($"LoadFail");
return default;
}
Debug.Log($"Load Complete {sceneName}");
return AddressablesManager.LoadSceneAsync(_addressableLocation[sceneName], loadMode, activateOnLoad);
}
public async UniTask<GameObject> LoadGameObjectAsync(string gameObjectName)
{
if (_addressableLocation.ContainsKey(gameObjectName) == false) return default;
var prefabGameObject =
await AddressablesManager.LoadAssetAsync<GameObject>(_addressableLocation[gameObjectName]);
var gameObject = PoolManager.Instance.spawnObject(prefabGameObject);
return gameObject;
}
public async UniTask<T> LoadUIPrefabAsync<T>() where T : UIBase
{
var uiName = PublicStaticMethod.GetTypeName<T>();
if (_addressableLocation.ContainsKey(uiName) == false) return default;
var prefabGameObject = await AddressablesManager.LoadAssetAsync<GameObject>(_addressableLocation[uiName]);
var gameObject = PoolManager.Instance.spawnObject(prefabGameObject);
var uiComponent = gameObject.GetComponent<T>();
return uiComponent;
}
C#
복사
리소스 매니저는 다음과 같은 규칙을 따릅니다.
•
UniTask를 기준으로 모든 로드가 수행됩니다.
•
각 타입별로 특별한 컨트롤이 필요한 경우, 리소스 매니저에서 관리합니다.
Addressable에서 로드하는 방식이 비동기 방식이기 때문에 UniTask를 사용합니다.
또한, 코루틴 컨트롤이나 유니티에서 활용 가능한 방식 등에서도 Task보다 UniTask가 더욱 활용적이라고 생각하여 UniTask를 선택하였습니다.
각 타입별 특별한 컨트롤에 대해선 게임오브젝트와 UI들을 예시로 들겠습니다.
public async UniTask<GameObject> LoadGameObjectAsync(string gameObjectName)
{
if (_addressableLocation.ContainsKey(gameObjectName) == false) return default;
var prefabGameObject =
await AddressablesManager.LoadAssetAsync<GameObject>(_addressableLocation[gameObjectName]);
var gameObject = PoolManager.Instance.spawnObject(prefabGameObject);
return gameObject;
}
C#
복사
위 로직은 게임 오브젝트를 로드하는 코드입니다.
특이한 점은 어드레서블에서 프리팹을 로드한 후, 풀링 매니저를 통해 생성하고 반환한다는 것입니다.
풀링 매니저는 해당 게임 오브젝트가 이미 풀링되어 있다면, 풀링된 게임 오브젝트를 반환하고, 그렇지 않다면 게임 오브젝트를 생성한 후 풀링합니다.
결과적으로, 게임 오브젝트 로드 로직에는 어드레서블, 풀링, 게임 오브젝트 반환 기능이 모두 포함되어 있습니다.
따라서, 개발자는 게임 오브젝트를 호출할 때 프리팹 이름만으로 로드할 수 있습니다.
public async UniTask<T> LoadUIPrefabAsync<T>() where T : UIBase
{
var uiName = PublicStaticMethod.GetTypeName<T>();
if (_addressableLocation.ContainsKey(uiName) == false) return default;
var prefabGameObject = await AddressablesManager.LoadAssetAsync<GameObject>(_addressableLocation[uiName]);
var gameObject = PoolManager.Instance.spawnObject(prefabGameObject);
var uiComponent = gameObject.GetComponent<T>();
return uiComponent;
}
C#
복사
위 로직은 UI를 생성하는 코드입니다.
UI 생성 매니저에서 고려해야 할 사항은 클래스 이름을 사용하여 프리팹을 생성한다는 것입니다. 어드레서블과 풀 매니저 모두 이에 대한 대응이 되어 있습니다.
또한, 이 로직은 UI 매니저를 통해서만 사용되어야 합니다. 이에 대한 자세한 내용은 아래 UI 매니저 소개에서 확인할 수 있습니다.