Inventory Item Aciton

김민오·2022년 9월 19일
0

현재 구현한 인벤토리 컴포넌트는 아이템을 수집만하고 별다른 액션을 수행하지는 않는다.

따라서 수집한 아이템을 장착하거나, 아니면 사용시 특정 오브젝트를 스폰, 혹은 소비를 할 수 있는등 아이템을 통한 특정 액션이 가능해야된다.

어떻게 구현해야할까 생각을 많이해봤는데 아이템을 구조체로 만든만큼 순수하게 정보만 가지고 있는게 좋을 것 같아, 아이템 액션을 수행하는 컴포넌트를 따로 만들어 캐릭터에 부착하기로했다.

물론 구조체도 클래스처럼 메소드를 만들어서 사용할 수 있다는건 알지만 애초에 USTRUCT에서는 UFUNCTION을 활용할 수 없는것도 있고, 그러면 아이템을 구조체로 만든 의미가 없다고 생각해서...

일단 아이템 구조체에는 어떤 액션을 취할지를 나타내는 정보를 추가했다.

USTRUCT(BlueprintType)
struct FInventoryItem : public FTableRowBase, public IInventoryActionBase
{
	GENERATED_BODY()

public:
	FInventoryItem();

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FName ItemID;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FText Name;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		int32 Weight;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		int32 Value;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		UTexture2D* Thumbnail;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FText Description;

	// 추가된 아이템 액션 정보
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FString ItemAction;

	bool operator==(const FInventoryItem& OtherItem) const
	{
		if (ItemID == OtherItem.ItemID)
			return true;
		return false;
	}

};

이 문자열 값을 아이템 액션 컴포넌트의 Delegate Map Key로 사용하여 해당 Key값에 대응되는 함수를 실행시킬 것이다.

헤더 

DECLARE_DELEGATE(FItemActionDelegate)

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SCIFICOMBAT_API UItemActionComponent : public UActorComponent
{
	// . . . . 기본적으로 생성되는 부분은 생략
public:
	UPROPERTY()
	class ACombatCharacter* inventory_owner;

	UPROPERTY(BlueprintReadWrite)
	FInventoryItem selected_item;
	FORCEINLINE void SetSelectedItem(FInventoryItem item_info) { selected_item = item_info; }

	// 아이템 액션 델리게이트 맵
	TMap<FString, FItemActionDelegate> item_action_delegate_map;
public:

	void InitializeItemActionComponent(class ACombatCharacter* _inventory_owner);

	FItemActionDelegate CreateItemActionDelegate(FString action_name);
	
	void InitializeItemActionDelegates();

	// 아이템 액션 RPC
	UFUNCTION()
	void ExecuteItemAction(const FString& action_name);
	UFUNCTION(Server, Reliable)
	void ServerExecuteItemAction(const FString& action_name);
	UFUNCTION(NetMulticast, Reliable)
	void MulticastExecuteItemAction(const FString& action_name);
	UFUNCTION()
	void CallItemAction(const FString& action_name);
public:
	// Item Actions
	UFUNCTION()
	void ItemAction_SpawnObject();
	UFUNCTION()
	void ItemAction_AttachMesh();
	UFUNCTION()
	void ItemAction_Consume();
};

구현부

// 초기화 단계
void UItemActionComponent::InitializeItemActionComponent(class ACombatCharacter* _inventory_owner)
{
	inventory_owner = _inventory_owner;
	InitializeItemActionDelegates();
}

void UItemActionComponent::InitializeItemActionDelegates()
{
	item_action_delegate_map.Add("SpawnObj", CreateItemActionDelegate("ItemAction_SpawnObject"));
	item_action_delegate_map.Add("AttachMesh", CreateItemActionDelegate("ItemAction_AttachMesh"));
	item_action_delegate_map.Add("Consume", CreateItemActionDelegate("ItemAction_Consume"));
}

FItemActionDelegate UItemActionComponent::CreateItemActionDelegate(FString skill_name)
{
	FItemActionDelegate item_action_delegate;
	item_action_delegate.BindUFunction(this, FName(skill_name));
	return item_action_delegate;
}

// 아이템 액션
// 일단 로그로 함수가 실행되는지만 확인함
void UItemActionComponent::ItemAction_SpawnObject()
{
	// selected_item을 활용하여 오브젝트 스폰
	UE_LOG(LogTemp, Warning, TEXT("Spawn Action"));
}

void UItemActionComponent::ItemAction_AttachMesh()
{
	// selected_item을 활용하여 메시 어태치
	UE_LOG(LogTemp, Warning, TEXT("Attach Mesh Action"));
}

void UItemActionComponent::ItemAction_Consume()
{
	// selected_item을 활용하여 특정 값을 소비
	UE_LOG(LogTemp, Warning, TEXT("Consume Action"));
}

// 아이템 액션 RPC
void UItemActionComponent::ExecuteItemAction(const FString& action_name)
{
	ServerExecuteItemAction(action_name);
}

void UItemActionComponent::ServerExecuteItemAction_Implementation(const FString& action_name)
{
	MulticastExecuteItemAction(action_name);
}

void UItemActionComponent::MulticastExecuteItemAction_Implementation(const FString& action_name)
{
	CallItemAction(action_name);
}

void UItemActionComponent::CallItemAction(const FString& action_name)
{
	if (item_action_delegate_map[action_name].IsBound())
	{
		item_action_delegate_map[action_name].Execute();
	}
}

캐릭터 클래스에 새로 추가한 함수들 BlueprintCallable UFUNCTION 옵션이 지정되어 있어 UMG 블루프린트에서 바로 호출가능하다.

// 아이템 섬네일 하단부 버튼에서 호출되는 함수
void UInventoryComponent::SelectItem(int idx)
{
	is_item_select = true;
	selected_item = inventory[idx];
}

void UInventoryComponent::SelectItemReset()
{
	is_item_select = false;
}

// 아이템 사용 버튼을 누르면 호출되는 함수
void UInventoryComponent::UseItem()
{
	if (is_item_select)
	{
		//selected_item.InventoryAction.GetInterface()->UseItem();
		//selected_item.UseItem();
		inventory_owner->item_action_component->SetSelectedItem(selected_item);
		inventory_owner->item_action_component->ExecuteItemAction(selected_item.ItemAction);
		// 장착형
		// 소비형
		// 소환형
	}
}

결과

각 아이템 섬네일의 하단부를 클릭하여 선택한 뒤 Use 버튼을 눌러 아이템 액션 함수를 실행시켰다.

이제 실제로 아이템 액션을 제대로 구현하여 악세서리를 부착하거나 아이템을 소환하고, 아이템 선택 버튼을 클릭 시 섬네일 외곽선이 강조되거나 하는.. 그런 부분들이 필요해보인다.

profile
https://github.com/gimhema, https://gimhema.tistory.com/

0개의 댓글