Unity 비동기 씬/에셋 로딩 최적화
Unity에서 LoadScene()을 동기로 호출하면 프레임이 멈춥니다. LoadSceneAsync와 Addressables를 활용한 비동기 로딩으로 로딩 바, 페이드 효과, 스트리밍 레벨 등을 구현할 수 있습니다.
1. LoadSceneAsync 기본
섹션 제목: “1. LoadSceneAsync 기본”using UnityEngine;using UnityEngine.SceneManagement;using System.Collections;
public class SceneLoader : MonoBehaviour{ public IEnumerator LoadSceneWithProgress(string sceneName) { AsyncOperation op = SceneManager.LoadSceneAsync(sceneName); op.allowSceneActivation = false; // 로드 완료 후 자동 전환 방지
while (!op.isDone) { // progress는 0~0.9 (allowSceneActivation = false일 때) float progress = Mathf.Clamp01(op.progress / 0.9f); UpdateProgressBar(progress);
// 로드 완료 시 전환 허용 if (op.progress >= 0.9f) { yield return new WaitUntil(() => Input.anyKeyDown); op.allowSceneActivation = true; }
yield return null; } }
void UpdateProgressBar(float value) { /* UI 갱신 */ }}2. async/await 기반 씬 로딩
섹션 제목: “2. async/await 기반 씬 로딩”using UnityEngine;using UnityEngine.SceneManagement;using System.Threading.Tasks;
public class AsyncSceneManager : MonoBehaviour{ public async Task LoadSceneAsync(string sceneName, System.IProgress<float> progress = null) { var op = SceneManager.LoadSceneAsync(sceneName); op.allowSceneActivation = false;
while (op.progress < 0.9f) { progress?.Report(op.progress / 0.9f); await Task.Yield(); }
progress?.Report(1f); op.allowSceneActivation = true;
// 씬 완전 로드 대기 while (!op.isDone) await Task.Yield(); }}3. Addressables 비동기 로딩
섹션 제목: “3. Addressables 비동기 로딩”using UnityEngine;using UnityEngine.AddressableAssets;using UnityEngine.ResourceManagement.AsyncOperations;using UnityEngine.ResourceManagement.ResourceProviders;
public class AddressableLoader : MonoBehaviour{ // 씬 로드 public async void LoadAddressableScene(string address) { var handle = Addressables.LoadSceneAsync(address, UnityEngine.SceneManagement.LoadSceneMode.Additive);
while (!handle.IsDone) { Debug.Log($"로딩: {handle.PercentComplete * 100:F0}%"); await Task.Yield(); }
if (handle.Status == AsyncOperationStatus.Succeeded) Debug.Log("씬 로드 완료"); else Debug.LogError("씬 로드 실패"); }
// 에셋 로드 및 캐시 private AsyncOperationHandle<GameObject> _prefabHandle;
public async Task<GameObject> LoadPrefabAsync(string address) { _prefabHandle = Addressables.LoadAssetAsync<GameObject>(address); await _prefabHandle.Task; return _prefabHandle.Result; }
void OnDestroy() { // 반드시 해제 if (_prefabHandle.IsValid()) Addressables.Release(_prefabHandle); }}4. 씬 전환 페이드 효과
섹션 제목: “4. 씬 전환 페이드 효과”using UnityEngine;using UnityEngine.UI;using System.Collections;
public class FadeSceneTransition : MonoBehaviour{ [SerializeField] CanvasGroup fadeCanvas;
public IEnumerator TransitionTo(string sceneName) { // 페이드 아웃 yield return StartCoroutine(Fade(0f, 1f, 0.5f));
var op = SceneManager.LoadSceneAsync(sceneName); op.allowSceneActivation = false;
while (op.progress < 0.9f) yield return null;
op.allowSceneActivation = true; yield return new WaitUntil(() => op.isDone);
// 페이드 인 yield return StartCoroutine(Fade(1f, 0f, 0.5f)); }
IEnumerator Fade(float from, float to, float duration) { float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; fadeCanvas.alpha = Mathf.Lerp(from, to, elapsed / duration); yield return null; } fadeCanvas.alpha = to; }}5. 에셋 사전 로드 (Preloading)
섹션 제목: “5. 에셋 사전 로드 (Preloading)”public class AssetPreloader : MonoBehaviour{ readonly Dictionary<string, AsyncOperationHandle> _cache = new();
public async Task PreloadAsync(IEnumerable<string> addresses) { var tasks = new List<Task>();
foreach (var addr in addresses) { if (_cache.ContainsKey(addr)) continue;
var handle = Addressables.LoadAssetAsync<Object>(addr); _cache[addr] = handle; tasks.Add(handle.Task); }
await Task.WhenAll(tasks); }
public T Get<T>(string address) where T : Object { if (_cache.TryGetValue(address, out var handle)) return handle.Result as T; return null; }}6. 메모리 관리 체크리스트
섹션 제목: “6. 메모리 관리 체크리스트”| 항목 | 설명 |
|---|---|
Addressables.Release() | 로드한 에셋은 반드시 해제 |
UnloadUnusedAssets() | 씬 전환 후 호출 |
allowSceneActivation | 준비 전 화면 전환 방지 |
| 씬 Additive 모드 | 대형 씬을 청크로 분할 로드 |
비동기 씬 로딩의 핵심은 allowSceneActivation = false로 전환을 제어하고 진행도를 UI에 반영하는 것입니다. Addressables를 활용하면 빌드 크기를 줄이고 런타임 스트리밍이 가능해집니다. 에셋 핸들은 사용 후 반드시 Release해 메모리 누수를 방지하세요.