PART 4 · 강의 2/4

Streaming 최적화

비동기 에셋 로딩으로 로딩 화면 없는 게임을 구현합니다

01

FStreamableManager

비동기 로딩의 핵심

⭐ 단일 에셋 비동기 로드
코드 숨기기
FStreamableManager& Manager = UAssetManager::GetStreamableManager(); // 비동기 로드 요청 TSharedPtr<FStreamableHandle> Handle = Manager.RequestAsyncLoad( AssetPath, FStreamableDelegate::CreateUObject( this, &AMyActor::OnAssetLoaded ) );
여러 에셋 비동기 로드
코드 보기
TArray<FSoftObjectPath> AssetsToLoad; AssetsToLoad.Add(Asset1.ToSoftObjectPath()); AssetsToLoad.Add(Asset2.ToSoftObjectPath()); AssetsToLoad.Add(Asset3.ToSoftObjectPath()); TSharedPtr<FStreamableHandle> Handle = Manager.RequestAsyncLoad( AssetsToLoad, FStreamableDelegate::CreateUObject( this, &AMyActor::OnAssetsLoaded ) );
로딩 규칙

플레이어가 게임 실행 중 볼 수 있는 상황에서는 반드시 Async 사용! 로딩 스크린 뒤에서만 Sync 사용 가능.

02

Asset Manager

Primary Asset 관리

Primary Asset 로드/언로드
코드 보기
// Primary Asset 비동기 로드 UAssetManager::Get().LoadPrimaryAsset( PrimaryAssetId, TArray<FName>(), // 추가 번들 FStreamableDelegate::CreateUObject( this, &AMyActor::OnPrimaryAssetLoaded ) ); // 언로드 UAssetManager::Get().UnloadPrimaryAsset(PrimaryAssetId);

Primary Asset 타입 등록

DefaultGame.ini 설정
코드 보기
[/Script/Engine.AssetManagerSettings] +PrimaryAssetTypesToScan=(PrimaryAssetType="Weapon",AssetBaseClass=/Script/MyGame.WeaponDataAsset,bHasBlueprintClasses=False,Directories=((Path=/Game/Data/Weapons))) +PrimaryAssetTypesToScan=(PrimaryAssetType="Character",AssetBaseClass=/Script/MyGame.CharacterDataAsset,bHasBlueprintClasses=False,Directories=((Path=/Game/Data/Characters)))
03

Streaming 설정

프로젝트 설정 최적화

⭐ DefaultEngine.ini Streaming 설정
코드 숨기기
[/Script/Engine.StreamingSettings] # Event Driven Loader - 로드 시간 50% 단축 s.AsyncLoadingThreadEnabled=True # Asynchronous Loading Thread - 로드 속도 2배 s.AsyncLoadingUseFullTimeLimit=True # 시간 제한 (ms) s.AsyncLoadingTimeLimit=5.0 # 프레임당 최대 패키지 수 s.MaxAsyncLoadingTimeSlice=2.0
로드 시간 단축

Event Driven Loader와 비동기 로딩을 함께 사용하면 로드 시간을 최대 50% 단축할 수 있습니다.

04

로딩 최적화 패턴

실전 비동기 로딩 전략

대규모 프로젝트에서는 체계적인 로딩 전략이 필요합니다. 레벨 전환, 스폰 시스템, UI 등 각 상황에 맞는 패턴을 사용해야 합니다.

// 프리로드 매니저 - 다음 레벨 에셋 미리 로드 void UPreloadManager::PreloadNextLevel(const FName& LevelName) { TArray<FPrimaryAssetId> AssetsToPreload; GetAssetsForLevel(LevelName, AssetsToPreload); for (const FPrimaryAssetId& AssetId : AssetsToPreload) { UAssetManager::Get().LoadPrimaryAsset( AssetId, TArray<FName>{"Preload"}, FStreamableDelegate::CreateUObject( this, &UPreloadManager::OnAssetPreloaded, AssetId ) ); } } // 로딩 진행률 추적 float UPreloadManager::GetLoadProgress() const { if (TotalAssets == 0) return 1.0f; return (float)LoadedAssets / (float)TotalAssets; }
Handle 관리 핵심

FStreamableHandle을 TSharedPtr로 보관하고, 에셋이 불필요해지면 Handle을 Release하세요. Handle이 모두 해제되면 GC가 에셋을 수거할 수 있습니다.

로드 우선순위

AsyncLoadingThreadEnabled=True 상태에서 모든 에셋이 동시에 로드 요청되면 I/O 병목이 발생합니다. AsyncLoadingTimeLimit을 적절히 설정하여 프레임 히칭을 방지하세요.

SUMMARY

핵심 요약

  • FStreamableManager: 비동기 에셋 로딩의 핵심 클래스
  • RequestAsyncLoad: 단일/다중 에셋 비동기 로드
  • Asset Manager: Primary Asset 타입 관리 및 로드
  • Event Driven Loader: 로드 시간 50% 단축
  • Handle 관리: TSharedPtr로 보관, 해제 시 GC 수거 가능
  • 규칙: 게임 실행 중에는 항상 Async!
다음 단계

다음 강의에서는 텍스처 메모리 관리와 Virtual Textures를 다룹니다.

PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: FStreamableManager 비동기 로드

TSoftObjectPtr로 5개 이상의 StaticMesh를 참조하는 Actor를 만들고, RequestAsyncLoad()로 일괄 비동기 로드를 구현하세요. 로드 완료 콜백에서 각 컴포넌트에 메시를 할당합니다.

실습 2: Primary Asset 등록

UPrimaryDataAsset을 상속한 WeaponDataAsset을 만들고, DefaultGame.ini에 PrimaryAssetTypesToScan으로 등록하세요. LoadPrimaryAsset()으로 비동기 로드를 테스트합니다.

심화 과제

레벨 전환 시 다음 레벨에 필요한 에셋을 미리 로드하는 PreloadManager를 구현하세요. 로딩 진행률을 UI에 표시하고, AsyncLoadingTimeLimit을 조절하여 프레임 히칭 없이 로드하세요.