Unity의 Addressables(정식 명칭: Addressable Asset System) 은 리소스를 효율적으로 로딩·관리·배포할 수 있게 도와주는 Unity의 공식 에셋 관리 시스템이다.

주소를 통해 코드에서 에셋을 직접 참조하지 않고 문자열이나 키 기반으로 에셋을 로드할 수 있다.
Addressables.LoadAssetAsync<GameObject>("EnemyPrefab");
에셋의 경로나 배치가 변경되더라도, 주소만 유지하면 코드 변경 없이 로드가 가능하다.


Windows > Asset Management > Addressables > Groups

InstantiateAsync, LoadAssetAsync 등을 통해 에셋을 비동기 로딩Addressables.Release로 해제하여 메모리 누수 방지var handle = Addressables.InstantiateAsync("EnemyPrefab");
// ...
Addressables.Release(handle);기존 플젝에서 Resources.Load을 사용하던 로직에서 Addressables로 변경하는 경우 동기→비동기 로직 변경으로 골머리를 좀 앓을 수도 있음. UniTask를 적극 활용하는 것을 추천.
https://github.com/Iosif2510/CitrusHeaven

<Doodle God>이나 <Infinite Craft>같은 원소 조합하기 계열의 단순한 드래그/드롭 게임을 뚝딱뚝딱 만들어보았음


각 Citrus 데이터는 ScriptableObject Asset 형태로 저장되며, 해금된 Citrus 목록 및 조합식에서는 각 Citrus의 이름만을 저장
이때 CitrusData는 어드레서블로 지정되어 Assets/GameData/Citrus/{이름}.asset 주소를 부여
public static async UniTask<CitrusData> FindCitrusByNameAsync(string name)
{
var handle = Addressables.LoadAssetAsync<CitrusData>($"Assets/GameData/Citrus/{name}.asset");
await handle.ToUniTask();
if (handle.Status == AsyncOperationStatus.Succeeded)
{
var result = handle.Result;
handle.Release();
return result;
}
Debug.LogError($"Failed to load CitrusData for {name}. Status: {handle.Status}");
return null;
}
FindCitrusByNameAsync를 사용해 필요한 경우에 이름으로 주소를 재구성해 비동기적으로 ScriptableObject 에셋을 로드하는 것이 가능
public static async UniTask<Dictionary<(CitrusData, CitrusData), CitrusData>> DeserializeCraftTableAsync(string json)
{
var table = JsonUtility.FromJson<CraftTableList>(json);
var craftTable = new Dictionary<(CitrusData, CitrusData), CitrusData>();
var tasks = new List<UniTask<(CitrusData, CitrusData, CitrusData)>>();
foreach (var entry in table.entries)
{
tasks.Add(UniTask.Create(async () =>
{
var taskResults = await UniTask.WhenAll(
FindCitrusByNameAsync(entry.operand1),
FindCitrusByNameAsync(entry.operand2),
FindCitrusByNameAsync(entry.result)
);
return (taskResults.Item1, taskResults.Item2, taskResults.Item3);
}));
}
var results = await UniTask.WhenAll(tasks);
foreach (var result in results)
{
if (result.Item1 != null && result.Item2 != null && result.Item3 != null)
{
craftTable.Add((result.Item1, result.Item2), result.Item3);
}
}
return craftTable;
}
Citrus의 이름만 담겨있는 CraftTable.json을 Dictionary<(CitrusData, CitrusData), CitrusData> 형태로 역직렬화하는 등으로 활용.
다만 json 파일 내에서 동일한 Citrus들이 여러번 중복되어 등장하는데, 이미 로드된 CitrusData를 캐싱하고 활용하는 것이 아니므로 위 코드는 최적화의 여지가 좀 더 있을듯…