[UE5] UI (2)

GamzaTori·2024년 11월 3일

UE5 C++

목록 보기
23/27

인벤토리 시스템 만들기

Inventory Slot 만들기

// h
public:
	UMyInventorySlotWidget(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

protected:
	virtual void NativeConstruct() override;

public:
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<USizeBox> SizeBox_Root;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UImage> Image_Slot;
    
//cpp
void UMyInventorySlotWidget::NativeConstruct()
{
	Super::NativeConstruct();

	SizeBox_Root->SetWidthOverride(50);
	SizeBox_Root->SetHeightOverride(50);
}
  • 인벤토리의 한 칸을 의미한다.
  • 이미지는 추후 아이템 아이콘으로 교체된다.

Inventory Slots 만들기

  • GridPanel_Slots에서는 Inventory slot을 여러개 들고 있음
// h
public:
	UMyInventorySlotsWidget(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

protected:
	virtual void NativeConstruct() override;

protected:
	UPROPERTY()
	TSubclassOf<UMyInventorySlotWidget> SlotWidgetClass;

	UPROPERTY()
	TArray<TObjectPtr<UMyInventorySlotWidget>> SlotWidgets;

	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UUniformGridPanel> GridPanel_Slots;

private:
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UCanvasPanel> CanvasPanel_Entries;

private:
	const int X_COUNT = 10;
	const int Y_COUNT = 5;
  • UMyInventorySlotWidget으로부터 파생된 클래스 자체를 들고있다.
  • 동적 생성한 인벤토리 슬롯을 TArray로 들고있는다.
  • GridPanel에 인벤토리 슬롯을 동적생성한다.
UMyInventorySlotsWidget::UMyInventorySlotsWidget(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	
	ConstructorHelpers::FClassFinder<UMyInventorySlotWidget> FindSlotWidgetClass(TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/UI/Item/Inventory/WBP_InventorySlot.WBP_InventorySlot_C'"));
	if (FindSlotWidgetClass.Succeeded())
	{
		SlotWidgetClass = FindSlotWidgetClass.Class;
	}
}

void UMyInventorySlotsWidget::NativeConstruct()
{
	Super::NativeConstruct();

	SlotWidgets.SetNum(X_COUNT * Y_COUNT);

	for (int32 y = 0; y < Y_COUNT; y++)
	{
		for (int32 x = 0; x < X_COUNT; x++)
		{
			int32 index = y * X_COUNT + x;

			UMyInventorySlotWidget* SlotWidget = CreateWidget<UMyInventorySlotWidget>(GetOwningPlayer(), SlotWidgetClass);
			SlotWidgets[index] = SlotWidget;
			GridPanel_Slots->AddChildToUniformGrid(SlotWidget, y, x);
		}
	}
}
  • 생성자에서 InventorySlot Widget 클래스의 정보를 FClassFinder를 통해 찾아 넣어준다.
  • 5x10 크기의 격자로 위젯을 생성해서 그리드 패널의 하위에 추가한다.

Item Drag & Drop 시스템 만들기

Object를 상속받아 Itme 클래스 만들기

  • 언리얼에서 자동으로 할당해주는 메모리를 사용하기 위해 Object를 상속
// h
UCLASS(BlueprintType)
class My_API UMyItemInstance : public UObject
{
	GENERATED_BODY()

public:
	UMyItemInstance(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

public:
	void Init(int32 InItemID);
	
public:
	UPROPERTY()
	int32 ItemID = 0;

	UPROPERTY()
	EItemRarity ItemRarity = EItemRarity::Junk;
};

// cpp
void UMyItemInstance::Init(int32 InItemID)
{
	if (InItemID <= 0)
		return;

	ItemID = InItemID;
	ItemRarity = EItemRarity::Common;
}
  • 아이템을 id와 타입을 가지고 관리한다.
// define.h
UENUM(BlueprintType)
enum class EItemRarity : uint8
{
	Junk,
	Poor,
	Common,
	Uncommon,
	Rare,
	Epic,
	Legendary,
	Unique,

	Count	UMETA(Hidden)
};
  • Count는 개수를 셀 때 사용하고 UMETA(Hidden) 키워드를 이용해 숨길 수 있다

Subsystem을 상속받아 인벤토리 만들기

// h
public:
	/** Implement this for initialization of instances of the system */
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	/** Implement this for deinitialization of instances of the system */
	virtual void Deinitialize() override;

	// TEMP
	void AddDefaultItems();

	const TArray<TObjectPtr<UMyItemInstance>>& GetItems() { return Items; }

protected:
	UPROPERTY()
	TArray<TObjectPtr<UMyItemInstance>> Items;
    
// cpp
void UMyInventorySubsystem::AddDefaultItems()
{
	// Test 용도
	TObjectPtr<UMyItemInstance> Item = NewObject<UMyItemInstance>();
	Item->Init(100);

	Items.Add(Item);
}
  • WorldSubsystem을 상속받았기 때문에 World의 생명주기를 따라간다.
  • 아이템의 원본 데이터는 서브시스템이 가지고 있고 UI에서 아이템을 전달받아 사용한다.

GameMode의 초기화 부분에 Inventory Subsystem 초기화하기

// h
public:
	virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;
    
// cpp
void AMyGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
	Super::InitGame(MapName, Options, ErrorMessage);

	UMyInventorySubsystem* Inventory = Cast<UMyInventorySubsystem>(USubsystemBlueprintLibrary::GetWorldSubsystem(this, UMyInventorySubsystem::StaticClass()));
	if (Inventory)
	{
		Inventory->AddDefaultItems();
	}
}
  • 게임이 시작하면서 실행되기 때문에 Subsystem을 초기화 하기 좋다
  • GameInstance Subsystem이라면 GameInstance에서 받아오면 되지만 World의 경우 USubsystemBlueprintLibarary에서 받아올 수 있다
profile
게임 개발 공부중입니다.

0개의 댓글