Unreal TIL 19일차 - FInstancedStruct

yys·2026년 3월 23일

TIL

목록 보기
15/76

🔗 학습 날짜 인증(주제와 무관)

오늘 한 내용

  • 프로그래머스 CodeKata
  • Git 복습
  • UE5 인벤토리 시스템(개인 공부)

이번에는 인벤토리 시스템을 공부하는 도중 FInstancedStruct에 대한 내용이 나와서 추후에 자주 사용될 것 같아 정리해보려고 한다.

FInstancedStruct


FInstancedStruct는 UE5부터 제공하는 USTRUCT이다.
일반적인 USTRUCT와 달리, 구조체의 인스턴스를 동적으로 관리할 수 있다는 점이 특징이다.

즉, 다형성을 사용할 수 있을 뿐더러 가비지 컬렉터(GC)의 영향을 받지 않고 데이터만 저장하는 구조체의 특징을 지닌다는 점에서 UObject와 차이가 있다.

사용하기 이전에, FInstancedStruct는 'StructUtils' 모듈을 사용하기 때문에 Build.cs에 다음 코드를 추가해야 한다.
(5.5 이후 위 모듈이 엔진 기본 모듈인 'CoreUObject'로 통합되어 추가하지 않아도 된다.)

PublicDependencyModuleNames.AddRange(new string[] { /* ... */ , "StructUtils" });

아래는 여러가지 아이템의 정보를 담고 있는 구조체이다.

// InvenctoryComponent.h
#pragma once

#include "CoreMinimal.h"
#include "StructUtils/InstancedStruct.h" // 필수 헤더
#include "InventoryComponent.generated.h"

USTRUCT(BlueprintType)
struct FItemBase // 기본 클래스
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere)
    FName ItemName = "Unknown";
};

USTRUCT(BlueprintType)
struct FWeaponItem : public FItemBase // 무기 구조체
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere)
    float AttackDamage = 50.0f;
};

USTRUCT(BlueprintType)
struct FPotionItem : public FItemBase // 포션 구조체
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere)
    float HealAmount = 30.0f;
};

이 구조체를 바탕으로 현재 저장된 아이템의 리스트들을 출력해보는 코드를 작성해본다고 하자.

먼저 USTRUCT를 사용했을 때, 코드를 작성해보면 다음과 같다.

// InvenctoryComponent.h
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class UInventoryComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere)
    TArray<FItemBase> InventorySlots; // 저장된 아이템 리스트

    void PrintInventory(); // 아이템 출력
    
    /* 아이템 추가/삭제 함수 등등... */
};

// InvenctoryComponent.cpp

/* InventorySlots에 대검(FWeaponItem), 체력 회복 포션(FPotionItem)이 저장되었다고 가정
void UInventoryComponent::PrintInventory()
{
    for (const FItemBase& Item : NormalInventory)
    {
        UE_LOG(LogTemp, Log, TEXT("아이템 이름: %s"), *Item.ItemName.ToString());
    }
}

// 결과
// LogTemp: 아이템 이름: 대검
// LogTemp: 아이템 이름: 체력 회복 포션

위와 같이, FWeaponItem에 있는 AttackDamageFPotionItem에 있는 HealAmount가 슬라이싱되어 출력이 안된 모습을 볼 수 있다.

FInstancedStruct를 사용하면 다음과 같은 코드를 작성할 수 있다.

// InvenctoryComponent.h
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class UInventoryComponent : public UActorComponent
{
    GENERATED_BODY()

public:
	// BaseStruct 메타 지정자로 블루프린트 에디터에서 FItemBase 유형의 데이터만 할당하도록 세팅
    UPROPERTY(EditAnywhere, meta = (BaseStruct = "/Script/YourProjectName.ItemBase")
    TArray<FInstancedStruct> InventorySlots; // 저장된 아이템 리스트

    void PrintInventory(); // 아이템 출력
    
    /* 아이템 추가/삭제 함수 등등... */
};

void UInventoryComponent::PrintInstancedInventory()
{
    for (const FInstancedStruct& ItemBox : InventorySlots)
    {
        if (const FWeaponItem* Weapon = ItemBox.GetPtr<FWeaponItem>())
        {
            UE_LOG(LogTemp, Warning, TEXT("무기: %s | 데미지: %f"), *Weapon->ItemName.ToString(), Weapon->AttackDamage);
        }
        else if (const FPotionItem* Potion = ItemBox.GetPtr<FPotionItem>())
        {
            UE_LOG(LogTemp, Warning, TEXT("포션: %s | 회복량: %f"), *Potion->ItemName.ToString(), Potion->HealAmount);
        }
    }
}
// 결과
// LogTemp: 무기: 대검 | 데미지: 15
// LogTemp: 포션: 체력 회복 포션 | 회복량: 20.000000

FInstancedStruct를 사용하면 GetPtr() 함수를 통해 래핑된 메모리 주소를 가져올 수 있기 때문에 데이터 손실을 방지할 수 있다.

FInstancedStruct가 아이템이나 스킬 유형과 같이 데이터 정보를 많이 요구할 때 꽤나 유용하기 때문에 나중에 RPG 프로젝트를 구현하게 될 때 매우 유용할 것 같다.

profile
게임 개발 지망생

0개의 댓글