[UE5] Longvinter 모작 - 요리 구현

·2023년 3월 26일

UE5

목록 보기
4/5
post-thumbnail

요리하기를 통한 아이템 획득

// 인벤토리에서 아이템 클릭 시 ItemClick 함수 호출됨
// ItemClick 함수 바인딩 한 부분
	mTileView->OnItemDoubleClicked().AddUObject(this, &UInventoryBase::ItemClick);

// CampFire Widget이 켜져있으면 인벤토리에서 해당 아이템 제거
// Craft 인벤토리에는 해당 아이템 추가
void UInventoryBase::ItemClick(UObject* Object)
{
	APlayerController* Controller = GetOwningLocalPlayer()->GetPlayerController(GetWorld());
	
	if (IsValid(Controller))
	{
		ALvPlayer* Character = Cast<ALvPlayer>(Controller->GetCharacter());
		if (IsValid(Character))
		{
			UItemDataBase* pData = Cast<UItemDataBase>(Object);

			if (IsValid(pData))
			{
				int ItemID = pData->GetItemID();
				ALvPlayerController* LvPlayerController = Cast<ALvPlayerController>(Controller);
				UCampFireBase* CampFireWidget = LvPlayerController->GetMainHUD()->GetCampFireWidget();
				if (true == CampFireWidget->IsVisible())
				{
					Character->GetInventoryComponent()->ServerRemoveItem(ItemID);
					Character->GetCraftComponent()->ServerAddItem(ItemID);
				}

				else
				Character->GetInventoryComponent()->ServerUseItem(ItemID);
			}
		}
	}
}

void UInventoryComponent::ServerRemoveItem_Implementation(int32 ItemID)
{
	mItems.RemoveSingle(ItemID);
}

// 아이템 추가 시 제작 가능한 아이템이 있는지 체크
// AllMatch되는 아이템이 있으면 요리 시간 Timer 세팅
void UCraftComponent::ServerAddItem_Implementation(int32 ItemID)
{
	mCraftItems.Add(ItemID);

	mCraftedItemID = -1;
	mProgressRatio = 0.f;
	GetOwner()->GetWorldTimerManager().ClearTimer(AllMatchTimerHandle);
	AllMatchTimerHandle.Invalidate();

	mCraftItems.Sort();

	UDataTable* Table = UInventory::GetInst(GetWorld())->GetCraftTable();
	FString Str;
	TArray<FCraftTable*> Rows; 
	
	Table->GetAllRows<FCraftTable>(Str, Rows);

	for (FCraftTable* CraftTable : Rows)
	{
		if (mCraftItems.Num() != CraftTable->RequiredItemList.Num())
			continue;

		bool AllMatch = true;

		for (int i = 0; i < CraftTable->RequiredItemList.Num(); i++)
		{
			if (mCraftItems[i] != CraftTable->RequiredItemList[i])
			{
				AllMatch = false;
			}
		}

		if (true == AllMatch)
		{
			ServerSetAllMatchTimer(mCraftItems.Num(), FCString::Atoi(*(CraftTable->Name.ToString())));
		}
	}
}

void UCraftComponent::ServerSetAllMatchTimer(int32 IngredientCount, int32 ItemID)
{
	mCookingTime = IngredientCount * 4.f;

	GetOwner()->GetWorldTimerManager().SetTimer(AllMatchTimerHandle, FTimerDelegate::CreateUObject(this, &UCraftComponent::ServerOnAllMatchTimerExpired, ItemID), mCookingTime, false);
}

// 타이머가 종료되면 CraftedItem이 세팅되고 ProgressBar는 100%가 됨
void UCraftComponent::ServerOnAllMatchTimerExpired(int32 ItemID)
{
	mCraftedItemID = ItemID;
	mProgressRatio = 1.f;
	GetOwner()->GetWorldTimerManager().ClearTimer(AllMatchTimerHandle);
	AllMatchTimerHandle.Invalidate();
}

// CraftedItemID가 세팅되었으므로 OnRep_CraftID 함수 실행
void UCraftComponent::OnRep_CraftID()
{
	OnCraftFinishedEvent.Broadcast(mCraftedItemID);
}

// 이벤트 구독 해 놓은 함수(OnCraftFinished) 실행
	Component->OnCraftFinishedEvent.AddUObject(this, &UCampFireBase::OnCraftFinished);

// UI 표출
void UCampFireBase::OnCraftFinished(int32 ItemID)
{
	mItemID = ItemID;
	if (ItemID == -1)
	{
		GetResultImage()->SetBrushFromTexture(nullptr);
		mCanGetCraftedItem = false;
	}
	else
	{
		mCanGetCraftedItem = true;

		FItemTable* ItemTable = UInventory::GetInst(GetWorld())->GetInfoItem(ItemID);
		UTexture2D* pTex2D = LoadObject<UTexture2D>(nullptr, *(ItemTable->TexturePath));

		GetResultImage()->SetBrushFromTexture(pTex2D);

		if(ItemTable->ItemType == EItemType::Food)
			mEatImg->SetVisibility(ESlateVisibility::Visible);
	}
}

// UI에 표출된 완성된 아이템을 클릭하면 OnClickedCraftItem 함수 호출
// 	바인딩 한 부분
	mResultBtn->OnClicked.AddDynamic(this, &UCampFireBase::OnClickedCraftItem);

// 아이템 획득 가능 상태면 인벤토리에 해당 아이템 추가
// 제작 인벤토리 ServerClear 함수 호출
void UCampFireBase::OnClickedCraftItem()
{
	if (true == mCanGetCraftedItem)
	{
		mCanGetCraftedItem = false;
		//FItemTable* Table = UInventory::GetInst(GetGameInstance())->GetInfoItem(mItemID);
		//UItemDataBase* pNewData = NewObject<UItemDataBase>();
		//pNewData->SetItemIconPath(Table->TexturePath);
		//pNewData->SetItemID(ItemID);

		APlayerController* Controller = GetOwningLocalPlayer()->GetPlayerController(GetWorld());
		ALvPlayer* Character = Cast<ALvPlayer>(Controller->GetCharacter());
		Character->GetInventoryComponent()->ServerAddItem(mItemID);
		Character->GetCraftComponent()->ServerClear();
		mEatImg->SetVisibility(ESlateVisibility::Collapsed);
	}
}

// ServerClear
void UCraftComponent::ServerClear_Implementation()
{
	mCraftItems.Empty();
	mCraftedItemID = -1;
	mProgressRatio = 0.f;
	GetOwner()->GetWorldTimerManager().ClearTimer(AllMatchTimerHandle);
	AllMatchTimerHandle.Invalidate();
}

요리 재료 제거

// 구독한 부분
	mCampFireTileView->OnItemClicked().AddUObject(this, &UCampFireBase::OnCancelCraftItem);

// 넣은 요리 재료를 클릭하면 제작 인벤토리에서 해당 아이템 제거
// 플레이어 인벤토리에 해당 아이템 추가
void UCampFireBase::OnCancelCraftItem(UObject* Object)
{
	UItemDataBase* ItemInfo = Cast<UItemDataBase>(Object);
	int32 ItemID = ItemInfo->GetItemID();

	APlayerController* Controller = GetOwningLocalPlayer()->GetPlayerController(GetWorld());
	ALvPlayer* PlayerCharacter = Cast<ALvPlayer>(Controller->GetCharacter());
	if (IsValid(PlayerCharacter))
	{
		UCraftComponent* CraftComponent = Cast<UCraftComponent>(PlayerCharacter->GetCraftComponent());
		if(IsValid(CraftComponent))
			CraftComponent->ServerRemoveItem(ItemID);

		UInventoryComponent* InventoryComponent = Cast<UInventoryComponent>(PlayerCharacter->GetInventoryComponent());
		if (IsValid(InventoryComponent))
			InventoryComponent->ServerAddItem(ItemID);
	}
}

// 아이템 변화에 따른 UI 업데이트
void UCampFireBase::OnItemsChanged(TArray<int32> Items)
{
	mCampFireTileView->ClearListItems();

	for (int32 Item : Items)
	{
		FItemTable* Table = UInventory::GetInst(GetGameInstance())->GetInfoItem(Item);
		UItemDataBase* pNewData = NewObject<UItemDataBase>();
		pNewData->SetItemIconPath(Table->TexturePath);
		pNewData->SetItemID(Item);
		pNewData->SetItemType(Table->ItemType);

		mCampFireTileView->AddItem(pNewData);
	}
}

요리 실패

(Case 1) 요리 도중 움직였을 때
(Case 2) 완성된 요리를 가져가지 않은 채로 움직였을 때

void UMainHUDBase::NativeTick(const FGeometry& _geo, float _DeltaTime)
{
	Super::NativeTick(_geo, _DeltaTime);

	UCharacterMovementComponent* MovementComponent = Character->GetCharacterMovement();
	bool isMoving = MovementComponent->Velocity.Size() > 0;
	if (isMoving)
	{
		if (mCampFire->IsVisible())
		{
			TArray<int32> AllItems = Character->GetCraftComponent()->GetCraftItems();
			for (int32 Item : AllItems)
			{
				Character->GetInventoryComponent()->ServerAddItem(Item);
			}
			Character->GetCraftComponent()->ServerClear();
			mCampFire->SetVisibility(ESlateVisibility::Collapsed);
		}

		{
		if (mSgtLakeVendor->IsVisible())
			mSgtLakeVendor->SetVisibility(ESlateVisibility::Collapsed);
		}
	}
}

1개의 댓글

comment-user-thumbnail
2023년 12월 6일

안녕하세요 롱빈터 모작 작업 진행하려고 하는데 혹시 캐릭터, 맵, 아이템 등 리소스들은 어떻게 구하셨는지 알려주실 수 있나요?

답글 달기