#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/DataTable.h"
#include "Inventory/InventoryAction/InventoryActionBase.h"
#include "ItemCraftRecipe.generated.h"
/**
*
*/
USTRUCT(BlueprintType)
struct FItemCraftRecipe : public FTableRowBase
{
GENERATED_BODY()
public:
FItemCraftRecipe();
UPROPERTY(Category = RecipeInfo, EditAnywhere, BlueprintReadWrite)
int32 RecipeID;
UPROPERTY(Category = RecipeInfo, EditAnywhere, BlueprintReadWrite)
TMap<FName, int32> needs;
UPROPERTY(Category = RecipeInfo, EditAnywhere, BlueprintReadWrite)
TSubclassOf<AActor> target_item;
UPROPERTY(Category = RecipeInfo, EditAnywhere, BlueprintReadWrite)
UTexture2D* Thumbnail;
UPROPERTY(Category = RecipeInfo, EditAnywhere, BlueprintReadWrite)
FText Name;
};
아이템을 제작하기 위한 레시피의 구조체이다.
needs는 target_item을 만들기위한(=스폰) 재료들에 대한 맵인데, 재료의 이름을 키로 제작에 필요한 수량을 Value로 두었다.
아이템 제작 시스템 구현을 위해서 Inventory Action Component를 수정했다.
Inventory Action Component 헤더
class SCIFICOMBAT_API UItemActionComponent : public UActorComponent
{
. . . . .
public:
// Item Craft
UFUNCTION(BlueprintCallable)
void SelectRecipe(const FItemCraftRecipe& recipe_info);
UFUNCTION(Server, Reliable)
void ServerSelectRecipe(TSubclassOf<AActor> item_class);
UFUNCTION(NetMulticast, Reliable)
void MulticastSelectRecipe(TSubclassOf<AActor> item_class);
UFUNCTION(BlueprintCallable)
bool CheckItemCraftCondition();
UFUNCTION(BlueprintCallable)
void ManufactureIngredient();
UFUNCTION(BlueprintCallable)
void UseIngredient(int32 need_quantity, int32 inventory_idx);
UFUNCTION(Server, Reliable)
void ServerUseIngredient(int32 need_quantity, int32 inventory_idx);
UFUNCTION(NetMulticast, Reliable)
void MulticastUseIngredient(int32 need_quantity, int32 inventory_idx);
UFUNCTION(BlueprintCallable)
void CraftItem(const FVector& create_loc);
UFUNCTION(Server, Reliable)
void ServerCraftItem(const FVector& create_loc);
UFUNCTION(NetMulticast, Reliable)
void MulticastCraftItem(const FVector& create_loc);
}
아이템 제작 핵심 함수들 구현부분
bool UItemActionComponent::CheckItemCraftCondition()
{
// 현재 아이템이 제작 가능한지를 체크하는 함수이다.
int check_count = 0;
// 장비 제작을 위해서 필요한 재료들이 현재 인벤토리 내부에 존재하는지 확인한다.
for (auto& elem : selected_recipe.needs)
{
for (int i = 0; i < inventory_owner->inventory_component->inventory.Num(); i++)
{
// 재료를 가지고 있다면
if (inventory_owner->inventory_component->inventory[i].Name.ToString() == elem.Key.ToString())
{
// 그리고 가지고 있는 재료가 레시피의 요구량 만큼 가지고 있다면
if (inventory_owner->inventory_component->inventory[i].Quantity >= elem.Value)
{
check_count++;
//IngredientUpdate(i, elem.Value);
//selected_ingredient_idxs.Add(i);
//selected_ingredient_qauntities.Add(elem.Value);
}
}
}
}
if (check_count == selected_recipe.needs.Num())
{
// check_count가 레시피의 재료 종류 수와 일치한다면 제작 조건을 만족함.
return true;
}
else
{
IngredientReset();
//selected_ingredient_idxs.Empty();
//selected_ingredient_qauntities.Empty();
}
return false;
}
// 레시피의 요구량 만큼 인벤토리 내부의 재료들을 감소시키는 함수
void UItemActionComponent::ManufactureIngredient()
{
// 레시피 내부를 돌면서
for (auto& Elem : selected_recipe.needs)
{
for (int i = 0; i < inventory_owner->inventory_component->inventory.Num(); i++)
{
// 레시피의 요구량만큼 재료수를 삭감
if (inventory_owner->inventory_component->inventory[i].Name.ToString() == Elem.Key.ToString())
{
int32 need_qanty = Elem.Value;
int32 result = inventory_owner->inventory_component->inventory[i].Quantity - need_qanty;
inventory_owner->inventory_component->inventory[i].Quantity = result;
}
}
}
// 인벤토리 내부를 돌면서 0보다 적은 재료수가 있다면 해당 아이템을 Remove함
for (int i = 0; i < inventory_owner->inventory_component->inventory.Num(); i++)
{
if (inventory_owner->inventory_component->inventory[i].Quantity <= 0)
{
inventory_owner->inventory_component->inventory.RemoveAt(i);
}
}
}
// 아이템 제작 로직 중 가장 마지막에 실행된다.
void UItemActionComponent::CraftItem(const FVector& create_loc)
{
ServerCraftItem(create_loc);
}
void UItemActionComponent::ServerCraftItem_Implementation(const FVector& create_loc)
{
MulticastCraftItem(create_loc);
}
void UItemActionComponent::MulticastCraftItem_Implementation(const FVector& create_loc)
{
// 제작된 아이템을 스폰한다.
if (inventory_owner->HasAuthority())
{
UWorld* world = GetWorld();
FRotator spawn_rot = FRotator(0.f, 0.f, 0.f);
if (world)
{
world->SpawnActor<AActor>(
craft_item_class,
create_loc,
spawn_rot
);
}
}
}
테이블 데이터로 보는 FItemCraftRecipe
target_item을 제작하기 위해 추가한 재료들
아이템 제작과 관련된정보들, 함수들은 Blueprint에서도 읽을 수 있게 UFUNCTION 옵션을 설정한다음 User Widget에 바인딩하여 사용했다.