하드 레퍼런스의 문제점
class BISHOUJO_DOOM_API ATestCharacter : public AActor { GENERATED_BODY() public: ATestCharacter(); protected: virtual void BeginPlay() override; public: virtual void Tick(float DeltaTime) override; public: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") USkeletalMesh* WeaponMesh; public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") USkeletalMeshComponent* MeshComponent; };
ATestCharacter
는 WeaponMesh
를 하드 레퍼런스로 가지고 있다.
UCLASS() class BISHOUJO_DOOM_API ATestCharacterManager : public AActor { GENERATED_BODY() public: ATestCharacterManager(); protected: virtual void BeginPlay() override; public: virtual void Tick(float DeltaTime) override; private: UPROPERTY(EditAnywhere) TSubclassOf TestClass; };
ATestCharacterManager
는 ATestCharacter
의 클래스를 참조한다.
TSubClassOf
: 클래스의 메타데이터와 타입 정보만 참조.
- 클래스 타입을 변수로 저장하고 인스턴스 생성 시 사용.
- CDO(기본 오브젝트) 포함.
- CDO의 모든 하드 레퍼런스 에셋들이 함께 로드됨.
TestMap
의 사이즈맵에 TestCharacterManager
밑의 TestCharacter
의 SkeletalMesh
가 포함된다. 맵이 로딩될 때, 같이 로드 된다는 얘기이다.

소프트 레퍼런스로 해결
class BISHOUJO_DOOM_API ATestCharacter : public AActor { GENERATED_BODY() public: ATestCharacter(); protected: virtual void BeginPlay() override; public: virtual void Tick(float DeltaTime) override; void OnCharacterAssetsLoaded(); public: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") TSoftObjectPtr WeaponMesh; // UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") // USkeletalMesh* WeaponMesh; };
WeaponMesh
를 소프트 레퍼런스로 변경하였다.
TestMap
의 사이즈맵에 TestCharacter
의 메시가 포함되지 않는 것을 볼 수 있다.

소프트 레퍼런스 에셋을 비동기로 로딩하는 방법
void ATestCharacter::BeginPlay() { Super::BeginPlay(); // 로드할 에셋들의 경로를 수집 TArray AssetsToLoad; if (!WeaponMesh.IsNull()) { AssetsToLoad.Add(WeaponMesh.ToSoftObjectPath()); } if (AssetsToLoad.Num() > 0) { // 비동기 로딩 시작 UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] 스켈레탈 메시 %d개 로딩중....."), AssetsToLoad.Num()); UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] 로딩 시작 시간 : %f"),GetWorld()->GetTimeSeconds()); UAssetManager& AssetManager = UAssetManager::Get(); FStreamableManager& StreamableManager = AssetManager.GetStreamableManager(); auto AllAssetsLoadHandle = StreamableManager.RequestAsyncLoad( AssetsToLoad, FStreamableDelegate::CreateUFunction(this, FName("OnCharacterAssetsLoaded")) ); UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] 로딩중에도 게임 계속 실행중.....")); } } void ATestCharacter::OnCharacterAssetsLoaded() { UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] 캐릭터의 스켈레탈 메시 로딩 완료")); UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] 로딩 완료 시간 : %f"),GetWorld()->GetTimeSeconds()); if (WeaponMesh.IsValid()) { MeshComponent->SetSkeletalMesh(WeaponMesh.Get()); } else { UE_LOG(LogTemp, Warning, TEXT("[SOFT_REF] Weapon Mesh is unvalid.")); } }
AssetManager
를 사용해서 비동기로 로딩할 수 있다.

동기로 로딩하지 않는 이유는 로딩할 에셋이 큰 경우 게임이 끊기는 현상이 발생할 수 있기 때문이다.