상점기능 구매 기능을 추가 해보겠습니다
Player가 거래를 하므로 해당 거래 로직을 Player로직을 해보겠습니다
TPSPlayer.h
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Status")
int64 CurrentMoney = 9999;
UFUNCTION(BlueprintCallable)
void UpdateMoney(int64 inputVal);
TPSPlayer.cpp
void ACTPSPlayer::UpdateMoney(int64 inputVal)
{
int64 _result;
_result = CurrentMoney + inputVal;
if (_result < 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT(" Not Enough Money "));
}
else
{
CurrentMoney = _result;
}
}
플레이어로직에 Inventory 로직을 제어할 경우
따로 만들고 그 Component를 붙여줘서 재 사용성을 늘리는 로직을 짜보자
InventoryActorComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ItemData.h"
#include "InventoryActorComponent.generated.h"
USTRUCT(BlueprintType)
struct FInventoryItem
{
GENERATED_BODY()
// 아이템의 데이터
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
FItemData ItemData;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
int32 Quantity;
FInventoryItem()
: ItemData(), Quantity(1) // 기본 수량은 1로 한다
{}
};
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class MAGICIAN_PROJECT_API UInventoryActorComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UInventoryActorComponent();
// 아이템의 고유 ID를 키로 하는 인벤토리 맵
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
TMap<int32, FInventoryItem> Inventory;
// DataTable로 부터 아이템을 로드
UFUNCTION(BlueprintCallable, Category = "Inventory")
void LoadItemFromDataTable(UDataTable* ItemDataTable);
// 인벤토리에 아이템 추가
UFUNCTION(BlueprintCallable, Category = "Inventory")
void AddItemToInventory(int32 ItemID, int32 Quantity);
// 인벤토리에 아이템 제거
UFUNCTION(BlueprintCallable, Category = "Inventory")
void RemoveItemFromInventory(int32 ItemID, int32 Quantity);
// 인벤토리가 가득 찼는지 확인
UFUNCTION(BlueprintCallable, Category = "Inventory")
bool IsInventoryFull() const;
// 인벤토리의 최대 크기
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
int32 MaxInventorySize;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
Map (맵) :
- Map은 키-값(key-value) 쌍을 저장하는 데이터 구조로, 각 키는 해당하는 값과 연관됩니다. Unreal Engine의 TMap 클래스는 해시맵을 나타냅니다. 이는 특정 키를 기반으로 값을 검색하고, 매우 빠른 검색 시간을 제공
- 특징
- 각 요소는 특정 키를 기반으로 저장됩니다. 각 키는 유일해야 합니다.
- 데이터의 삽입, 검색 및 삭제가 빠릅니다.
- 순서가 보장되지 않으며, 순차적으로 반복하는 것은 기대되지 않습니다.
- 중복된 키를 가질 수 없지만(Unique), 값은 중복될 수 있습니다.
InventoryActorComponent.cpp
void UInventoryActorComponent::LoadItemFromDataTable(UDataTable* ItemDataTable)
{
if (ItemDataTable)
{
TArray<FName> RowNames = ItemDataTable->GetRowNames();
for (const FName& RowName : RowNames)
{
FItemData* ItemData = ItemDataTable->FindRow<FItemData>(RowName, "");
if (ItemData)
{
// ItemID를 키로 하여 인벤토리에 추가 ( 기본 수량 1 )
FInventoryItem NewItem;
NewItem.ItemData = *ItemData;
NewItem.Quantity = 1; // 처음 로드 시 기본 수량을 1로 설정
Inventory.Add(ItemData->ItemID, NewItem);
}
}
}
}
void UInventoryActorComponent::AddItemToInventory(int32 ItemID, int32 Quantity)
{
// 인벤토리가 가득 찼는지 확인
if (IsInventoryFull())
{
UE_LOG(LogTemp, Warning, TEXT("Inventory is full"));
return;
}
// 이미 인벤토리에 해당 아이템이 있는지 확인
if (Inventory.Contains(ItemID))
{
FInventoryItem& ExitingItem = Inventory[ItemID];
// 아이템이 스택 가능할 경우 수량을 추가
if (ExitingItem.ItemData.bIsStackable)
{
ExitingItem.Quantity += Quantity;
UE_LOG(LogTemp, Warning, TEXT("Increased quantity of item with ID %d to %d "), ItemID, Quantity);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Item with ID %d is not stackable!"), ItemID);
}
}
else
{
// DataTable 에서 해당 ID의 아이템을 로드하여 추가
FInventoryItem NewItem;
NewItem.ItemData.ItemID = ItemID; // 기본 데이터 설정
NewItem.Quantity = Quantity;
Inventory.Add(ItemID, NewItem);
UE_LOG(LogTemp, Warning, TEXT("Added new item with ID %d, Quantity : %d "), ItemID, Quantity);
}
}
void UInventoryActorComponent::RemoveItemFromInventory(int32 ItemID, int32 Quantity)
{
if (Inventory.Contains(ItemID))
{
FInventoryItem& ItemData = Inventory[ItemID];
// 아이템의 수량을 감소시키고 0 이하일 경우 제거
ItemData.Quantity -= Quantity;
if (ItemData.Quantity <= 0)
{
Inventory.Remove(ItemID);
UE_LOG(LogTemp, Warning, TEXT("Removed item with ID %d from inventory."), ItemID)
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Decrease quantity of item with ID %d to %d "), ItemID, Quantity);
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Item with ID %d not found in inventory. "), ItemID)
}
}
bool UInventoryActorComponent::IsInventoryFull() const
{
return Inventory.Num() >= MaxInventorySize;
}