Streaming 최적화
비동기 에셋 로딩으로 로딩 화면 없는 게임을 구현합니다
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 사용 가능.
Asset Manager
Primary Asset 관리
// Primary Asset 비동기 로드
UAssetManager::Get().LoadPrimaryAsset(
PrimaryAssetId,
TArray<FName>(), // 추가 번들
FStreamableDelegate::CreateUObject(
this,
&AMyActor::OnPrimaryAssetLoaded
)
);
// 언로드
UAssetManager::Get().UnloadPrimaryAsset(PrimaryAssetId);
Primary Asset 타입 등록
[/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)))
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% 단축할 수 있습니다.
로딩 최적화 패턴
실전 비동기 로딩 전략
대규모 프로젝트에서는 체계적인 로딩 전략이 필요합니다. 레벨 전환, 스폰 시스템, 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;
}
FStreamableHandle을 TSharedPtr로 보관하고, 에셋이 불필요해지면 Handle을 Release하세요. Handle이 모두 해제되면 GC가 에셋을 수거할 수 있습니다.
AsyncLoadingThreadEnabled=True 상태에서 모든 에셋이 동시에 로드 요청되면 I/O 병목이 발생합니다. AsyncLoadingTimeLimit을 적절히 설정하여 프레임 히칭을 방지하세요.
핵심 요약
- FStreamableManager: 비동기 에셋 로딩의 핵심 클래스
- RequestAsyncLoad: 단일/다중 에셋 비동기 로드
- Asset Manager: Primary Asset 타입 관리 및 로드
- Event Driven Loader: 로드 시간 50% 단축
- Handle 관리: TSharedPtr로 보관, 해제 시 GC 수거 가능
- 규칙: 게임 실행 중에는 항상 Async!
다음 강의에서는 텍스처 메모리 관리와 Virtual Textures를 다룹니다.
도전 과제
배운 내용을 직접 실습해보세요
TSoftObjectPtr로 5개 이상의 StaticMesh를 참조하는 Actor를 만들고, RequestAsyncLoad()로 일괄 비동기 로드를 구현하세요. 로드 완료 콜백에서 각 컴포넌트에 메시를 할당합니다.
UPrimaryDataAsset을 상속한 WeaponDataAsset을 만들고, DefaultGame.ini에 PrimaryAssetTypesToScan으로 등록하세요. LoadPrimaryAsset()으로 비동기 로드를 테스트합니다.
레벨 전환 시 다음 레벨에 필요한 에셋을 미리 로드하는 PreloadManager를 구현하세요. 로딩 진행률을 UI에 표시하고, AsyncLoadingTimeLimit을 조절하여 프레임 히칭 없이 로드하세요.