본 코드는 Lyra 샘플 프로젝트의 LyraAssetManager기반으로 작성 됨
AssetManager 동작 방식
AssetManager 등록
DefaultEngine.ini에 등록해서 엔진이 기본 AssetManager 대신 사용
AssetManagerClassName=/Script/ProjectFT.FTAssetManager
PrimaryAssetTypesToScan 등록
- 패키징에서 빠질 수 있는 에셋을 명시적으로 Cook 대상에 포함시키기
- AssetManager가 타입/ID 기반으로 쉽게 찾고 로드할 수 있게 만들기
[/Script/Engine.AssetManagerSettings]
+PrimaryAssetTypesToScan=(PrimaryAssetType="FTGameData",AssetBaseClass="/Script/ProjectFT.FTGameDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Data/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))
+PrimaryAssetTypesToScan=(PrimaryAssetType="FTItem",AssetBaseClass="/Script/ProjectFT.FTItemDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Data/Items")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))
.ini 설정이 되어 있으면 아래와 같이 호출 가능.
if (UFTAssetManager* AssetManager = Cast<UFTAssetManager>(GEngine->AssetManager))
{
return *AssetManager;
}
UE_LOG(LogFTAsset, Fatal, TEXT("Invalid AssetManagerClassName. It must be set to FTAssetManager."));
GameDataPath
GameDataPath는 .ini에서 설정 가능한 소프트 레퍼런스
UPROPERTY(Config)
TSoftObjectPtr<UFTGameDataAsset> GameDataPath;
.ini에 설정
[/Script/ProjectFT.FTAssetManager]
GameDataPath=/Game/Data/DA_GameData.DA_GameData
GameData
로드된 게임 데이터 에셋을 캐싱
UPROPERTY(Transient) // 런타임에만 유지됨
TObjectPtr<UFTGameDataAsset> GameData = nullptr;
LoadedAssets
로드한 에셋을 보관하는 Set
LoadedAssets에 넣어서 AssetManager가 해당 에셋을 계속 참조하게 해서 GC 대상이 안되게 함
UPROPERTY()
TSet<TObjectPtr<const UObject>> LoadedAssets;
LoadedAssetsCritical
Mutex가 들어있는 FCriticalSection 사용
LoadedAssets 접근을 보호하기 위한 락
FCriticalSection LoadedAssetsCritical
AssetManager::GetAsset
1. Load Object
기존:
UTexture2D* Icon = LoadObject<UTexture2D>(
nullptr,
TEXT("/Game/UI/Texture/T_ItemIcon.T_ItemIcon")
);
AssetManager/SoftReference 사용:
UTexture2D* Icon = UFTAssetManager::GetAsset(ItemData.ItemIcon);
차이:
- 경로 문자열이 코드에서 사라짐
- 에셋 위치 변경에 강해짐
ItemIcon이TSoftObjectPtr<UTexture2D>라 타입이 명확함
2. ConstructorHelpers X
기존:
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshFinder(
TEXT("/Game/Assets/SM_Item.SM_Item")
);
ItemMesh->SetStaticMesh(MeshFinder.Object);
AssetManager 사용:
UStaticMesh* Mesh = UFTAssetManager::GetAsset(ItemData.ItemMesh);
ItemMesh->SetStaticMesh(Mesh);
차이:
- 생성자에서 강제 로드하지 않음
- 필요한 시점에 로드 가능
- 생성자 코드가 에셋 경로에 묶이지 않음
3. 동기 로드, 비동기 로드 선택 가능
작고 즉시 필요한 에셋:
UTexture2D* Icon = UFTAssetManager::GetAsset(ItemData.ItemIcon);
큰 에셋이나 화면 전환 중 비동기 로드:
UFTAssetManager::Get().LoadAssetAsync<UStaticMesh>(
ItemData.ItemMesh,
[this](UStaticMesh* LoadedMesh)
{
if (!LoadedMesh)
{
return;
}
ItemMesh->SetStaticMesh(LoadedMesh);
});
차이:
- 기존에는
LoadObject/TryLoad로 순간 끊김이 생김 - 비동기 로드를 선택하면 UI나 로딩 화면과 연결 가능
4. Cast
기존:
UObject* LoadedObject = SoftPath.TryLoad();
UFTItemDataAsset* ItemData = Cast<UFTItemDataAsset>(LoadedObject);
AssetManager 사용:
UFTItemDataAsset* ItemData = UFTAssetManager::GetAsset(ItemDataRef);
차이:
- 사용처에서
Cast반복이 줄어듦 - 타입이
TSoftObjectPtr<UFTItemDataAsset>에 이미 들어 있음
5. Widget 생성 코드
기존:
UClass* WidgetClass = LoadClass<UUserWidget>(
nullptr,
TEXT("/Game/UI/HUD/WBP_MainHUD.WBP_MainHUD_C")
);
UUserWidget* Widget = CreateWidget<UUserWidget>(PC, WidgetClass);
AssetManager 사용:
TSubclassOf<UFTMainHUDWidget> HUDClass =
UFTAssetManager::GetSubclass(GameData.MainHUDWidgetClass);
UFTMainHUDWidget* HUD =
CreateWidget<UFTMainHUDWidget>(PC, HUDClass);
차이:
_C문자열을 직접 만들 필요 없음- WidgetClass를 DataAsset에서 지정 가능
- UIManager가 어떤 위젯을 띄울지 데이터로 바꿀 수 있음
6. 아이템/퀘스트 데이터 접근 방식
기존:
UFTItemDataAsset* ItemData = LoadObject<UFTItemDataAsset>(
nullptr,
TEXT("/Game/Data/Items/DA_Milk.DA_Milk")
);
AssetManager 사용:
FPrimaryAssetId ItemAssetId(TEXT("FTItem"), TEXT("DA_Milk"));
UFTAssetManager& AssetManager = UFTAssetManager::Get();
AssetManager.LoadPrimaryAsset(
ItemAssetId,
{},
FStreamableDelegate::CreateLambda([]()
{
// 로드 완료 후 사용
}));
또는 이미 soft reference가 있으면:
UFTItemDataAsset* ItemData = UFTAssetManager::GetAsset(ItemDataRef);
차이:
- 특정 에셋을 이름/타입으로 관리 가능
- 모든 FTItem을 스캔해서 목록화가 가능
UFTAssetManager 장점
에셋 보관
기존:
UObject* Loaded = Path.TryLoad();
// 어디에서도 UPROPERTY로 잡지 않으면 GC 대상이 될 수 있음
AssetManager 사용:
UTexture2D* Icon = UFTAssetManager::GetAsset(ItemData.ItemIcon, true);
차이:
bKeepInMemory = true면 AssetManager가LoadedAssets에 보관- 반복 사용 에셋은 다시 로드하지 않게 관리 가능
에셋 직접 로드 X
기존:
void AFTItemActor::BeginPlay()
{
UFTItemDataAsset* Data = LoadObject<UFTItemDataAsset>(
nullptr,
TEXT("/Game/Data/Items/DA_Cleaner.DA_Cleaner")
);
ApplyItemData(Data);
}
개선:
void AFTItemActor::ApplyItemData(UFTItemDataAsset* ItemData)
{
if (!ItemData)
{
return;
}
UStaticMesh* Mesh = UFTAssetManager::GetAsset(ItemData->ItemData.ItemMesh);
ItemMeshComponent->SetStaticMesh(Mesh);
}
차이:
- Actor는 “어디서 데이터를 찾을지”를 몰라도 됨
- 스폰하는 쪽, 인벤토리, 상점, DataAsset이 참조를 넘겨줌
- Actor 책임이 줄어듦
로딩 화면 생성 가능
PX 방식:
AssetManager가 LoadingWidget 생성
AssetManager가 에셋 로드
AssetManager가 OpenLevel
우리 방향:
GameFlowSubsystem이 로딩 요청
UIManager가 LoadingWidget 표시
AssetManager가 에셋 로드만 담당
GameFlowSubsystem이 레벨 전환
차이:
- AssetManager가 UI/레벨 전환을 직접 하지 않음
- 실패/탈출/레벨 전환 규칙과 충돌하지 않음
에셋 테스트/디버깅이 획일화 됨
기존에는 “경로가 맞나?”를 코드에서 봐야 합니다.
"/Game/UI/HUD/WBP_MainHUD.WBP_MainHUD_C"
AssetManager 사용 후에는:
- DataAsset에 참조가 제대로 들어갔는지 확인
PrimaryAssetTypesToScan설정이 맞는지 확인- AssetManager 로그로 로드 성공/실패 확인
예상 디버그 함수:
UFTAssetManager::DumpLoadedAssets();
코드 사용 요약
// 경로 문자열로 직접 로드
LoadObject / LoadClass / TryLoad / ConstructorHelpers
→
// 타입 있는 참조를 AssetManager로 로드
TSoftObjectPtr / TSoftClassPtr / PrimaryAssetId / GetAsset / GetSubclass / LoadAssetAsync
Actor나 UI 코드는 에셋 경로를 덜 알고, DataAsset과 Manager가 참조와 로딩 책임을 가져감.
반응형
'Unreal Engine' 카테고리의 다른 글
| UE Input 1 (0) | 2026.06.23 |
|---|---|
| GameplayTag Static vs GameplayTag Extern (0) | 2026.06.22 |
| UE Game play Framework 2 (0) | 2026.06.18 |
| UE Game play Framework 1 (0) | 2026.06.17 |
| GAS 2 (0) | 2026.06.16 |