


AXZCharacter::AXZCharacter()
{
...
for ( EModularMeshType ModuleType : ModuleTypes )
{
...
UXZSkeletalMeshComponent* MeshComponent = CreateDefaultSubobject<UXZSkeletalMeshComponent>(*ComponentName);
MeshComponent->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform);
SkeletalMeshComponents.Add(ModuleType, MeshComponent);
}
SkeletalMeshComponents.Add(EModularMeshType::Body, GetMesh());
}
SkeletalMeshComponent와 연결하여 수행한다.EModularMeshType 값의 이름 기반으로 SkeletalMeshComponent 와 연결하여 관리하는 방식으로 동적으로 처리한다.USkeletalMeshComponent* UXZModularComponent::GetSkeletalMeshComponent(EModularMeshType ModuleType) const
{
if ( AXZCharacter* Character = Cast<AXZCharacter>(GetOwner()) )
{
return Character->GetSkeletalMeshComponent(ModuleType);
}
return nullptr;
}
void UXZModularComponent::Attach(EModularMeshType ModuleType, int32 ItemID)
{
... 예외 처리
if ( const UXZDataManager* DataManager = UGameInstance::GetSubsystem<UXZDataManager>(GetWorld()->GetGameInstance()) )
{
const FName ModuleIDName = FName(*FString::FromInt(ItemID));
// ItemID의 값으로 DataManager에서 Asset 경로를 가지고 온다.
if ( FItemTable_Module* ModuleAsset = DataManager->TryGetModuleAsset(ModuleIDName) )
{
ensure(SkeletalMeshComponent);
// 비동기 방식으로 애셋을 로드한다.
UXZAssetManager& AssetManager = UXZAssetManager::GetXZAssetManager();
FSoftObjectPath AssetPath = ModuleAsset->ASSETPATH;
AssetManager.GetStreamableManager().RequestAsyncLoad(AssetPath, FStreamableDelegate::CreateLambda([this, SkeletalMeshComponent, AssetPath]()
{
// 애셋 로드가 끝나면 Character의 SkeletalMeshComponent에 애셋을 설정한다.
AXZCharacter* Character = Cast<AXZCharacter>(GetOwner());
ensure(Character);
ensure(Character->GetMesh());
if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(AssetPath.TryLoad()))
{
SkeletalMeshComponent->SetSkeletalMesh(SkeletalMesh);
if (SkeletalMeshComponent != Character->GetMesh())
{
SkeletalMeshComponent->SetMasterPoseComponent(Character->GetMesh());
}
}
}));
}
}
}
EnumPtr을 사용하여 EModularMeshType에 해당하는 모듈을 반복문으로 순회하며 처리한다.void UXZModularComponent::BeginPlay()
{
Super::BeginPlay();
const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EModularMeshType"), true);
if (false == IsValid(EnumPtr) )
{
return;
}
for ( int32 i = 0; i < EnumPtr->NumEnums() - 1; ++i )
{
const FName ModuleTypeName = *EnumPtr->GetNameStringByIndex(i);
const EModularMeshType MeshType = static_cast<EModularMeshType>(i);
if ( UXZDataManager* DataManager = UGameInstance::GetSubsystem<UXZDataManager>(GetWorld()->GetGameInstance()) )
{
// DataManager에서 Base Module Item 정보를 가지고 온다.
if ( FItemTable_ModuleInfo* ModuleInfo = DataManager->TryGetModuleInfo(ModuleTypeName) )
{
// 획득 가능하지 않다면
if (false == ModuleInfo->Obtainable )
{
const int32 BaseModuleIndex = GetBaseModuleItemIndex(ModuleInfo->ID);
Attach(MeshType, BaseModuleIndex);
}
else
{
UE_LOG(LogTemp, Log, TEXT("Obtainable Module : [%s]"), *EnumPtr->GetNameStringByIndex(i));
}
}
}
}
}

ItemID를 잘못 넣어주면 해당하는 애셋을 찾지 못하게 되기 때문에 아래와 같은(ㅋㅋㅋ) 상황이 벌어진다 !
