Unreal Engine에서 객체 초기화 시점과 BeginPlay 시점의 차이를 이해하는 것은 매우 중요합니다. 이번 글에서는 왜 생성자에서 레벨 이름을 가져올 수 없는지, 그리고 BeginPlay
에서 FObjectFinder
를 사용할 수 없는 이유를 상세히 살펴보겠습니다. 또한, 이를 해결할 수 있는 방법까지 제공합니다. 이 글을 통해 UE5 개발 과정에서 자주 발생하는 실수를 방지할 수 있으면 좋겠네요.
아이템을 스폰하려고 하는데 각 월드마다 다른 아이템 조합을 스폰하고 싶었습니다. 예를들어 level001 에서는 열쇠, 손전등을 스폰하고 level002 에서는 거울, 연필을 스폰하려고 했습니다. 스폰할 아이템은 DataTable로 만들어 두었기 때문에 각 레벨마다 DataTable을 만들어주고 여기에 접근하려고 했습니다.
자주자주 보게되는 언리얼의 액터 라이프사이클 |
Unreal Engine에서 생성자는 객체가 메모리에 할당되는 동안 호출됩니다. 이 단계에서는 아직 레벨 정보가 완전히 초기화되지 않았기 때문에, GetWorld()
와 같은 함수가 유효하지 않습니다. 따라서, 레벨 이름이나 월드와 관련된 다른 정보에 접근할 수 없습니다.
AMyActor::AMyActor()
{
// 이 시점에서 GetWorld()는 아직 유효하지 않음
if (GetWorld())
{
FString LevelName = GetWorld()->GetMapName();
UE_LOG(LogTemp, Warning, TEXT("Level Name: %s"), *LevelName);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("GetWorld() is not valid in constructor."));
}
}
이 코드에서 GetWorld()
는 생성자 내에서는 항상 nullptr
를 반환하므로, 레벨 이름을 가져올 수 없습니다.
FObjectFinder
는 일반적으로 정적 애셋 로드에 사용됩니다. 이는 생성자나 클래스 초기화 시점에서 실행되어야 합니다. BeginPlay
는 게임이 시작될 때 호출되지만, FObjectFinder
는 이 시점에서는 이미 적절하게 작동하지 않습니다. 이 때문에, BeginPlay
에서 FObjectFinder
를 사용하는 것은 권장되지 않습니다.
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// BeginPlay에서 FObjectFinder 사용
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Path/To/Your/Mesh.Mesh"));
if (MeshAsset.Succeeded())
{
UE_LOG(LogTemp, Warning, TEXT("Mesh loaded successfully."));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to load mesh in BeginPlay."));
}
}
이 코드에서 FObjectFinder
는 정적 초기화 구문에 속해야 하는데, BeginPlay
에서 사용하면 의도한 대로 작동하지 않을 수 있습니다.
생성자에서 레벨 정보를 가져올 수 없기 때문에, 이를 BeginPlay
나 다른 초기화 함수에서 처리해야 합니다.
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// 이 시점에서는 GetWorld()가 유효함
if (GetWorld())
{
FString LevelName = GetWorld()->GetMapName();
UE_LOG(LogTemp, Warning, TEXT("Level Name: %s"), *LevelName);
}
}
AMyActor::AMyActor()
{
// 정적 자산 로드는 생성자나 클래스 초기화 시점에서 수행
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Path/To/Your/Mesh.Mesh"));
if (MeshAsset.Succeeded())
{
MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyMesh"));
MeshComponent->SetStaticMesh(MeshAsset.Object);
}
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// BeginPlay에서는 추가적인 초기화 작업을 수행
if (MeshComponent)
{
UE_LOG(LogTemp, Warning, TEXT("MeshComponent initialized in BeginPlay."));
}
}
생성자에서는 레벨이나 월드 정보를 가져올 수 없으며, GetWorld()
가 유효하지 않습니다.
FObjectFinder는 정적 자산 로드에 사용되며, 생성자나 클래스 초기화 시점에서 실행되어야 합니다.
레벨 정보는 BeginPlay에서 가져와야 하며, 정적 자산 로드는 생성자에서 처리해야 합니다.
아이템마다 어떤 레벨에서 쓰이는지에 대한 정보를 넣어야하지 않을까합니다.
이러한 차이를 이해하고 각각의 시점에서 적절한 작업을 수행하는 것이 중요합니다.
이 글을 통해 UE5 개발에서 흔히 발생하는 문제들을 예방하고 더 나은 코드를 작성할 수 있기를 바랍니다!!