Unreal - 인벤토리(2) ( 아이템 추가하기 )

2025. 11. 23. 15:06·Unreal 프로젝트 다이어리/두번째 프로젝트

이전글에서 이어집니다

2025.11.22 - [Unreal 프로젝트 다이어리/두번째 프로젝트] - Unreal - 인벤토리 (크기변경하기, 창옮기기)

 

Unreal - 인벤토리 ( 크기변경하기, 창옮기기 )

인벤토리를 구현해보겠습니다1인 개발이다보니 기획도 스스로 해야했습니다 (어쩔수있나요)인벤토리 초기 구상도입니다인벤토리 구상도 인벤토리 기능인벤토리의 현재 기능은 이와 같습니다

lucodev.tistory.com

 

아이템슬롯에 아이템을 추가해보겠습니다

 

구현한 내용

  • 아이템 획득 시 해당 아이템의 최대 스택 수 만큼 한 슬롯에 저장됩니다
  • 아이템번호로 아이템을 구분합니다
  • 아이템을 인벤토리에 추가 및 삭제 가 가능합니다

 

구현방식

  1. 아이템을 먹었을 때 ItemID, Count를 전달받습니다
  2. SlotItem(TArray<FItemSlot>)에서 동일한 아이템을 찾습니다
  3. ItemData에서 최대 스택을 확인합니다
  4. 이미 있는 슬롯이면 MaxStack 까지 합칩니다
  5. Count가 아직 남아있으면 빈슬롯을 찾아 넣습니다
  6. 남은 Count가 있으면 인벤토리 공간 부족 처리로 넘어갑니다
  7. UI를 업데이트합니다

 

사용한 클래스

InventoryComponent 인벤토리 기능의 두뇌역할, 실제 로직 실행장소
InventoryWidget 모든 SlotWidget을 보유하고 관리하는 인벤토리 전체 UI
ItemData 아이템의 고정된 속성을 제공하는 데이터베이스 역할
SlotWidget 화면에 보이는 인벤토리 '한 칸'을 그리는 위젯
ItemSlot 인벤토리 '한 칸' 을 표현하는 구조체

 

 

구현

먼저 게임에서 사용할 모든 아이템 데이터를 제작해주었습니다

아이템은 각각의 ID를 보유하며 itemName, Type, maxStack등 여러가지 속성을 가집니다

UENUM(BlueprintType)
enum class EItemType : uint8
{
	Consumable,
	Upgrade,
	Quest,
	Money
};

USTRUCT(BlueprintType)
struct FItemData : public FTableRowBase
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 itemID;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FString itemName;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	EItemType itemType;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int32 maxStack;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FString itemDescription;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	UTexture2D* itemIcon;

};

 

인벤토리를 배열(TArray)로 관리하기위해 

FItemSlot 즉 인벤토리의 한 칸 에 들어있는 아이템 정보를 저장하는 구조체를 만들어주었습니다

 

어떤아이템이 들어있는가? -> itemID로 판단

몇개들어있는가? -> inCount로 판단

비어있는칸인가? -> isEmpty()로 판단

아이템을 버리거나 이동하면? -> Clear()로 비움

USTRUCT(BlueprintType)
struct FItemSlot
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	int32 itemID = -1;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	int32 inCount = 0;

	bool isEmpty() const
	{
		return itemID < 0 || inCount <= 0;
	}

	void Clear()
	{
		itemID = -1;
		inCount = 0;
	}
};

 

인벤토리 컴포넌트에서 데이터테이블을 할당하고 

아이템 데이터 테이블을 읽어서 itemDataMap(아이디 -> 데이터) 로 저장해두었습니다

 

TMap<int32, FItemData> itemDataMap;

void UInventoryComponent::BeginPlay()
{
	Super::BeginPlay();
	InitializeInventory(baseInvenSlotCount);
}

void UInventoryComponent::InitializeInventory(int32 numSlots)
{
	baseInvenSlotCount = numSlots;
	items.SetNum(baseInvenSlotCount);

	if (itemDataTable)
	{
		static const FString contextString(TEXT("ItemDataInialize"));
		TArray<FItemData*> allItems;
		itemDataTable->GetAllRows<FItemData>(contextString, allItems);

		for (FItemData* row : allItems)
		{
			if (row)
				itemDataMap.Add(row->itemID, *row);
		}
	}
}

 

인벤토리의 특정 슬롯이 업데이트 되었다 라는 사실을

다른 UI에 알려주는 이벤트 시스템으로 델리게이트를 사용하여 인벤토리위젯을 바인딩한뒤 갱신합니다

 

인벤토리컴포넌트에 델리게이트를 달아줍니다

인벤토리컴포넌트.h의 클래스 상단 델리게이트를 추가해줍니다

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInventoryUpdated, int32, SlotIndex, FItemSlot, Item);

 

컴포넌트 내 델리게이트 변수를 선언해줍니다

UPROPERTY(BlueprintAssignable, Category = "Inventory")
FOnInventoryUpdated onInventoryUpdated;

 

 

아이템을 추가하거나 삭제할때 Broadcast하여 몇번째 슬롯이 바뀌었는지 구조체의 현재 상태를 알려주면됩니다

onInventoryUpdated.Broadcast(배열에서 몇 번째 슬롯이 바뀌었는지, FItemSlot 구조체의 현재 상태);

 

이제 아이템을 추가하는 핵심 AddItem함수를 만들어보았습니다

아이템을 인벤토리에 넣는데 스택 규칙을 지켜서 넣는 함수입니다

규칙은 이와 같습니다

1. 이미 같은 아이템이 있는 슬롯에 먼저 눌러담습니다

2. 그 다음 빈 슬롯을 찾아서 넣습니다

3. 각 슬롯이 변경되면델리게이트로 UI에게 알려서 UI를 업데이트합니다

bool UInventoryComponent::AddItem(int32 itemID, int32 count)
{
	if (!itemDataMap.Contains(itemID))
		return false;

	const FItemData& mapData = itemDataMap[itemID];
	int32 maxStack = mapData.maxStack;
	int32 remain = count;

	//스택계산
	for (int32 i = 0; i < items.Num(); i++)
	{
		FItemSlot& slot = items[i];
		if (slot.itemID == itemID && slot.inCount < maxStack)
		{
			int32 slotSpace = maxStack - slot.inCount;
			int32 addAmount = FMath::Min(slotSpace, remain);

			slot.inCount += addAmount;
			remain -= addAmount;

			onInventoryUpdated.Broadcast(i, slot);

			if (remain <= 0)
				return true;
		}
	}

	//빈슬롯에 새로 넣기 
	for (int32 i = 0; i < items.Num(); i++)
	{
		FItemSlot& slot = items[i];

		if (slot.isEmpty())
		{
			int32 addAmount = FMath::Min(maxStack, remain);

			slot.itemID = itemID;
			slot.inCount = addAmount;

			remain -= addAmount;

			onInventoryUpdated.Broadcast(i, slot);

			if (remain <= 0)
				return true;
		}
	}
	return false;
}

 

그런뒤 인벤토리 위젯에서 onInventoryUpdated 델리게이트를 받을수있게 바인드 하여 구독을 해줍니다

if (inventoryComp)
	inventoryComp->onInventoryUpdated.AddDynamic(this, &UInventoryWidget::OnInventoryUpdated);
void UInventoryWidget::OnInventoryUpdated(int32 slotIndex, FItemSlot item)
{
	if (!WrapBox_Inven)
		return;

	USlotWidget* slotWidget = Cast<USlotWidget>(WrapBox_Inven->GetChildAt(slotIndex));
	if (!slotWidget)
		return;

	const FItemData* itemData = inventoryComp->itemDataMap.Find(item.itemID);
	if (itemData)
		slotWidget->UpdateSlot(item, *itemData);
	else
		// 빈 슬롯 처리
		slotWidget->UpdateSlot(item, FItemData());
}

 

 

마지막으로 SlotWidget 슬롯을 업데이트 하여 이미지와 갯수Text를 업데이트 시켜주는 함수를 만들어주면 마무리가됩니다

void USlotWidget::UpdateSlot(const FItemSlot& inslot, const FItemData& inData)
{
	if (!Image_ItemSlot || !TextBlock_ItemCount)
		return;
	if (inslot.isEmpty())
	{
		Image_ItemSlot->SetBrushFromTexture(emptyTexture);
		TextBlock_ItemCount->SetText(FText::FromString(TEXT("")));
		return;
	}

	// 아이템이 있으면 아이템 이미지와 개수 표시
	if (inData.itemIcon)
		Image_ItemSlot->SetBrushFromTexture(inData.itemIcon);

	// 아이템 개수가 1 이상이면 표시, 1이면 빈 텍스트
	if (inslot.inCount > 1)
		TextBlock_ItemCount->SetText(FText::AsNumber(inslot.inCount));
	else
		TextBlock_ItemCount->SetText(FText::FromString(TEXT("")));

	
}

 

결과

현재 아이템을 먹는곳을 따로 구현하지않아 키보드 입력으로 아이템을 받아보겠습니다

1번 아이템, 그리고 7번 아이템을 받아보겠습니다

그리고 해당 아이템의 최대 스택은 1번은 12개 7번은 5개입니다

이번에는 ItemID5번과 ItemID14번을 1개, 100개씩 받아보겠습니다

해당 최대스택은 5, 255입니다

 

 

 

저작자표시 비영리 변경금지 (새창열림)

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글

Unreal - 인벤토리(4) ( 정렬, 삭제 )  (0) 2025.11.26
Unreal - 인벤토리(3) (드래그 앤 드롭)  (0) 2025.11.25
Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )  (2) 2025.11.22
Unreal - UI (HpWidget, PostureWidget)  (0) 2025.11.21
Unreal - StatComponent  (0) 2025.11.21
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - 인벤토리(4) ( 정렬, 삭제 )
  • Unreal - 인벤토리(3) (드래그 앤 드롭)
  • Unreal - 인벤토리(1) ( 크기변경하기, 창옮기기 )
  • Unreal - UI (HpWidget, PostureWidget)
lucodev
lucodev
언리얼 포폴개발 일기
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (236)
      • Unreal 프로젝트 다이어리 (132)
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (59)
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (5)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    unreal 세키로
    unreal 인벤토리
    언리얼 parkour
    언리얼 인벤토리
    unreal
    언리얼 비헤이비어트리
    unreal 파쿠르
    unreal npc
    언리얼 파쿠르
    언리얼 컷씬
    언리얼 behaviortree
    언리얼 시퀀스
    언리얼 세키로
    언리얼 상호작용
    언리얼 behavior tree
    언리얼
    언리얼 ui
    unreal 상호작용
    unreal inventory
    언리얼 인터렉션
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 인벤토리(2) ( 아이템 추가하기 )
상단으로

티스토리툴바