[ Unreal Engine 5 / #14 Event Dispatchers ]

SeungWoo·2024년 10월 24일

[ Ureal Engine 5 / 수업 ]

목록 보기
29/31
post-thumbnail

  • Event Dispatchers
    • 객체 간 통신을 쉽게 처리하기 위한 메커니즘
    • 다른 클래스의 함수를 호출시 나의 클래스 안에서 다른 클래스에 접근하거나, 인스턴화한뒤 함수를 호출하지만, Dispatchers는 바로 그 값을 받아 온다. 즉, 통신의 서버가 해당 클라이언트에서 신호가 오면 답을 바로 주는 형식처럼 해당 클래스에 작업을 처리한다. 그래서 다른 클래스를 접근하거나 만들지 않아도 되는 장점이 있다

  • WBP_Item 선언된 Money Spent를 WBP_ItemShop에서 Event Dispatchers를 사용하여 호출할 경우 WBP_Item 작업하지않고 응답만 받아와 WBP_ItemShop에서 작업을 수행하게 된다

  • 이벤트 (Event)
    • 이벤트는 객체 간 상호 작용 및 통신을 위한 메커니즘입니다.
    • 이벤트는 특정 상황이나 조건이 충족될 때 호출되며, 다른 객체들에게 그것이 발생했다는 신호를 보냅니다.
    • Unreal Engine의 이벤트는 Event Dispatcher를 통해 구현될 수 있으며, 이를 사용하여 객체 간에 데이터 및 행동을 교환할 수 있습니다
  • 비교 ( FUNCTION VS EVENET )
    • 목적
      • 함수 : 코드를 그룹화하고 재사용성을 높이기 위한 것
      • 이벤트 : 객체 간 상호 작용 및 통신을 위한 메커니즘
    • 호출 방법
      • 함수 : 직접 호출 - >주인
      • 이벤트 : 발생 시그널을 보내고, 해당 이벤트를 구독하고 있는 객체가 그것을 수신하여 처리
    • 사용 예시
      • 함수 : 일반적으로 연산을 수행하거나 값을 반환하는 등의 작업에 사용
      • 이벤트 : 상태 변경이나 특정한 상황이 발생했을 때 다른 객체들에게 알리는 데 사용

TPSPlayer.h

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
	class UInventoryActorComponent* DefaultInventoryTest;

TPSPlayer.cpp

ACTPSPlayer::ACTPSPlayer()
{
	... 생략
    
	DefaultInventoryTest = CreateDefaultSubobject<UInventoryActorComponent>(TEXT("DefaultInventoryComp"));
	DefaultInventoryTest->MaxInventorySize = 30; 
}

  • 기존에는 DataTable에 있는 Index로 하여금 아이템을 구분하고 그 값으로 찾고 추출했다 지금 부터 해당 Item 이름으로 하여금 아이템을 거래하고 구분하고 정리하는 로직으로 바꿔 보자
  • 쉽게 말해 변경된 Map구조에 따라서 InventoryActorComponent CPP를 수정해보자

InventoryActorComponent.h

publci:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
	TMap<FName, FInventoryItem> Inventory;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
	UDataTable* ItemDataTable;

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	FItemData LoadItemFromDataTable(FName ItemRowName);

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void AddItemToInventory(FName ItemRowName, int32 Quantity);

	UFUNCTION(BlueprintCallable, Category = "Inventory")
	void RemoveItemFromInventory(FName ItemRowName, int32 Quantity);

InventoryActorComponent.cpp

FItemData UInventoryActorComponent::LoadItemFromDataTable(FName ItemRowName)
{
	if (!ItemDataTable)
	{
		UE_LOG(LogTemp, Warning, TEXT("Invalid DataTable"));
		// 기본 값 반환 
		return FItemData();
	}

	//  DataTable에서 RowName에 해당하는 데이터를 찾습니다 
	FItemData* ItemData = ItemDataTable->FindRow<FItemData>(ItemRowName, TEXT("Item Lookup"));

	if (ItemData)
	{
		// 유효한 데이터 반환
		return *ItemData;
	}
	else
	{
		// 기본값 반환
		return FItemData();
	}
}
void UInventoryActorComponent::AddItemToInventory(FName ItemRowName, int32 Quantity)
{
	// 인벤토리가 가득 찼는지 확인 
	if (IsInventoryFull())
	{
		UE_LOG(LogTemp, Warning, TEXT("Inventory is full"));
		return;
	}

	// 이미 인벤토리에 해당 아이템이 있는지 확인
	if (Inventory.Contains(ItemRowName))
	{
		FInventoryItem& ExitingItem = Inventory[ItemRowName];

		// 아이템이 스택 가능할 경우 수량을 추가
		if (ExitingItem.ItemData.bIsStackable)
		{
			ExitingItem.Quantity += Quantity;
			UE_LOG(LogTemp, Warning, TEXT("Increased quantity of item with ID %s to %d "), *ItemRowName.ToString(), Quantity);
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Item with ID %d is not stackable!"), *ItemRowName.ToString());
		}
	}
	else
	{
		// DataTable에서 해당 RowName의 아이템을 로드하여 추가
		if (ItemDataTable)
		{
			// DataTable 에서 해당 ID의 아이템을 로드하여 추가
			FItemData ItemData = LoadItemFromDataTable(ItemRowName);
			FInventoryItem NewItem;
			NewItem.ItemData = ItemData; // 기본 데이터 설정
			NewItem.Quantity = Quantity;
			Inventory.Add(ItemRowName, NewItem);

			UE_LOG(LogTemp, Warning, TEXT("Added new item with ID %s, Quantity : %d "), *ItemRowName.ToString(), Quantity);
		}
	}
}
void UInventoryActorComponent::RemoveItemFromInventory(FName ItemRowName, int32 Quantity)
{
	// 인벤토리에서 해당 아이템이 존재하는지 확인
	if (Inventory.Contains(ItemRowName))
	{
		FInventoryItem& ItemData = Inventory[ItemRowName];

		// 아이템의 수량을 감소시키고 0 이하일 경우 제거
		ItemData.Quantity -= Quantity;
		if (ItemData.Quantity <= 0)
		{
			Inventory.Remove(ItemRowName);
			UE_LOG(LogTemp, Warning, TEXT("Removed item with ID %s from inventory."), *ItemRowName.ToString());
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Decrease quantity of item with ID %s to %d "), *ItemRowName.ToString(), Quantity);
		}
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("Item with ID %s not found in inventory. "), *ItemRowName.ToString());
	}
}

  • 이제는 연결 할 수 있을 것이다

  • 이제 버튼을 눌러 구매를 하면 goekd DefaultInventory에 해당 데이터 값과 Quantity가 올라가는 부분을 알 수 있다

Player Inventory

  • 만들어논 해당 이벤토리 위젯을 복사해 각각 이름을 지어준다
  • 기존에 아이템 위젯에 있던 가격은 수량으로 바꿀 예정이니 바인딩을 제거 하고

  • 해당 Quantity 변수를 새로 만든다

  • 기존에 있던 가격 변수 바인딩을 해제 하고 새로 선언한 Quantity변수에 바인딩

  • Quantity변수 설정

  • item Fetch 함수 블루프린트 에서 Quantity 제어

  • player 이벤토리에는 구매 기능이 필요없으므로 삭제하고 사진 처럼 블루 프린트를 제작한다

  • 위젯을 띄울 InputAction를 하나 제작 한다
profile
This is my study archive

0개의 댓글