본문 바로가기
개발이야기/언리얼 c++

언리얼C++: ConstructorHelpers를 사용해 에셋을 로딩해보자

by oddsilk 2024. 6. 18.

서론 :  컨텐츠 폴더의 에셋을 c++에서 사용하고 싶어

언리얼 엔진에서 c++로 클래스를 제작할때 컨텐츠 폴더의 에셋을 지정하는 것이다.

블루프린트에서는 스테틱메쉬나 스켈레탈 메쉬와 같은 컴포넌트들을 붙이고 드래그 앤 드롭 하거나 선택해주면 쉽게 에셋을 지정해줄 수 있었다.

 

하지만 c++은 어떻게 할 수 있을까??

 

ConstructorHelpers란?

언리얼 엔진 5.4에서 ConstructorHelpers 클래스는 주로 C++ 코드에서 객체를 생성할 때 리소스를 찾고 로드하는 데 사용됩니다. ConstructorHelpers는 주로 생성자에서 특정 자산(Asset)을 쉽게 로드할 수 있도록 도와줍니다. 공식 문서를 기반으로 ConstructorHelpers에 대해 자세히 설명하겠습니다.

1. FObjectFinder

FObjectFinder는 주어진 경로에서 특정 유형의 객체를 찾는 데 사용됩니다. 예를 들어, 특정 메시(Mesh)나 텍스처(Texture)를 찾는 경우에 사용됩니다.

ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube"));
if (MeshAsset.Succeeded())
{
    StaticMeshComponent->SetStaticMesh(MeshAsset.Object);
}

 

위 코드에서 FObjectFinder는 /Game/StarterContent/Shapes/Shape_Cube.Shape_Cube 경로에 있는 정적 메시(Static Mesh)를 찾습니다. 메시를 성공적으로 찾으면, StaticMeshComponent에 해당 메시를 설정합니다.

 여기서 경로는 어떻게 가져올 수 있을까?? 컨텐츠 폴더에 가서 원하는 에셋 "우클릭-> 레퍼런스복사" 를 클릭해준다

 

2. FClassFinder

FClassFinder는 주어진 경로에서 특정 유형의 클래스를 찾는 데 사용됩니다. 예를 들어, 특정 블루프린트 클래스나 C++ 클래스를 찾는 경우에 사용됩니다.

ConstructorHelpers::FClassFinder<APawn> PawnClass(TEXT("/Game/Blueprints/MyPawn.MyPawn_C"));
if (PawnClass.Succeeded())
{
    DefaultPawnClass = PawnClass.Class;
}

위 코드에서 FClassFinder는 /Game/Blueprints/MyPawn.MyPawn_C 경로에 있는 폰(Pawn) 클래스를 찾습니다. 클래스를 성공적으로 찾으면, 기본 폰 클래스로 설정합니다.

 

FObjectFinder와 FClassFinder는 다르다. 
가장 큰 차이점을 알 수 있는 부분은, 클래스를 가져올때 경로에 "_C"를 붙인다는 것이다

주의사항

  • ConstructorHelpers는 생성자에서만 사용해야 합니다. 이는 생성자가 호출될 때 객체를 로드하기 때문입니다.
  • 경로는 항상 /Game/으로 시작해야 합니다. 이는 게임 콘텐츠 디렉터리의 루트를 가리킵니다.
  • 경로 문자열은 텍스트 매크로(TEXT())를 사용하여 유니코드 문자열로 변환해야 합니다.
  • 리소스를 찾을 수 없을 경우 예외나 오류를 발생시키지 않으므로, Succeeded() 메서드를 사용하여 리소스가 성공적으로 로드되었는지 확인해야 합니다.

 

ConstructorHelpers를 사용하면 생성자 내에서 필요한 자산을 쉽게 로드하고 설정할 수 있어, 게임 개발 과정에서 코드의 가독성과 유지보수성을 높이는 데 도움이 됩니다.

 

 

 

 

 

실습

Unreal Engine에서 스켈레탈 메쉬의 레퍼런스 경로를 통해 생성자에서 메쉬를 설정하려면, ConstructorHelpers::FObjectFinder를 사용하여 메쉬를 로드하고, 해당 메쉬를 스켈레탈 메쉬 컴포넌트에 설정할 수 있습니다. 

  1. 헤더 파일 (.h)

먼저, 클래스의 헤더 파일에서 스켈레탈 메쉬 컴포넌트를 선언합니다.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MySkeletalMeshActor.generated.h"

UCLASS()
class MYPROJECT_API AMySkeletalMeshActor : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor's properties
    AMySkeletalMeshActor();
//--생략---//
    // Skeletal Mesh Component
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    USkeletalMeshComponent* SkeletalMeshComponent;
};

스켈레탈 메쉬 컴포넌트 생성:

  • SkeletalMeshComponent를 생성하고 RootComponent로 설정합니다.

 

 

다음으로, 클래스의 소스 파일에서 생성자 내에서 스켈레탈 메쉬를 로드하고 설정합니다.

#include "MySkeletalMeshActor.h"
#include "Components/SkeletalMeshComponent.h"
#include "UObject/ConstructorHelpers.h"

// Sets default values
AMySkeletalMeshActor::AMySkeletalMeshActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Create the Skeletal Mesh Component
    SkeletalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalMeshComponent"));
    RootComponent = SkeletalMeshComponent;

    // Set the Skeletal Mesh (replace the path with your own mesh path)
    static ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMeshAsset(TEXT("/Game/Path/To/Your/SkeletalMesh.SkeletalMesh"));
    if (SkeletalMeshAsset.Succeeded())
    {
        SkeletalMeshComponent->SetSkeletalMesh(SkeletalMeshAsset.Object);
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("Failed to load skeletal mesh"));
    }
}

 

  • 스켈레탈 메쉬 로드:
    • ConstructorHelpers::FObjectFinder를 사용하여 스켈레탈 메쉬를 로드합니다. 이때, 경로는 Unreal Engine 에디터에서 해당 자산의 경로를 복사하여 사용합니다. 예를 들어, /Game/Path/To/Your/SkeletalMesh.SkeletalMesh 형태입니다.
  • 스켈레탈 메쉬 설정:
    • 메쉬가 성공적으로 로드되면 SetSkeletalMesh 함수를 사용하여 스켈레탈 메쉬 컴포넌트에 설정합니다.
  • 에러 처리:
    • 메쉬 로드에 실패한 경우, 로그를 출력하여 경고 메시지를 표시합니다.