第一次提交
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Drops/GIS_CurrencyDropper.h"
|
||||
|
||||
#include "GIS_CurrencySystemComponent.h"
|
||||
#include "GIS_LogChannels.h"
|
||||
#include "Misc/DataValidation.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_CurrencyDropper)
|
||||
|
||||
void UGIS_CurrencyDropper::BeginPlay()
|
||||
{
|
||||
MyCurrency = UGIS_CurrencySystemComponent::GetCurrencySystemComponent(GetOwner());
|
||||
if (MyCurrency == nullptr)
|
||||
{
|
||||
GIS_CLOG(Warning, "Mising currency system component!");
|
||||
}
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void UGIS_CurrencyDropper::Drop()
|
||||
{
|
||||
if (AActor* PickupActor = CreatePickupActorInstance())
|
||||
{
|
||||
if (UGIS_CurrencySystemComponent* CurrencySys = UGIS_CurrencySystemComponent::GetCurrencySystemComponent(PickupActor))
|
||||
{
|
||||
CurrencySys->SetCurrencies(MyCurrency->GetAllCurrencies());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if WITH_EDITOR
|
||||
EDataValidationResult UGIS_CurrencyDropper::IsDataValid(FDataValidationContext& Context) const
|
||||
{
|
||||
if (PickupActorClass.IsNull())
|
||||
{
|
||||
Context.AddError(FText::FromString(FString::Format(TEXT("%s has no pickup actor class.!"), {*GetName()})));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
return Super::IsDataValid(Context);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Drops/GIS_DropperComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GIS_LogChannels.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_DropperComponent)
|
||||
|
||||
|
||||
UGIS_DropperComponent::UGIS_DropperComponent()
|
||||
{
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
SetIsReplicatedByDefault(true);
|
||||
}
|
||||
|
||||
void UGIS_DropperComponent::Drop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AActor* UGIS_DropperComponent::CreatePickupActorInstance_Implementation()
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
check(World);
|
||||
if (PickupActorClass.IsNull())
|
||||
{
|
||||
GIS_CLOG(Error, "missing PickupActorClass!");
|
||||
return nullptr;
|
||||
}
|
||||
UClass* PickupClass = PickupActorClass.LoadSynchronous();
|
||||
if (PickupClass == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "failed to load PickupActorClass!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FVector Origin = CalcDropOrigin();
|
||||
AActor* Pickup = World->SpawnActor<AActor>(PickupClass, FTransform(Origin + CalcDropOffset()));
|
||||
if (Pickup == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "failed to spawn pickup actor from PickupActorClass(%s)!", *PickupClass->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
return Pickup;
|
||||
}
|
||||
|
||||
FVector UGIS_DropperComponent::CalcDropOrigin_Implementation() const
|
||||
{
|
||||
if (IsValid(DropTransform))
|
||||
{
|
||||
return DropTransform->GetActorLocation();
|
||||
}
|
||||
|
||||
FVector OriginLocation = GetOwner()->GetActorLocation();
|
||||
|
||||
if (const ACharacter* Character = Cast<ACharacter>(GetOwner()))
|
||||
{
|
||||
OriginLocation.Z -= Character->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
||||
}
|
||||
else if (const UCapsuleComponent* CapsuleComponent = Cast<UCapsuleComponent>(GetOwner()->GetRootComponent()))
|
||||
{
|
||||
OriginLocation.Z -= CapsuleComponent->GetScaledCapsuleHalfHeight();
|
||||
}
|
||||
return OriginLocation;
|
||||
}
|
||||
|
||||
FVector UGIS_DropperComponent::CalcDropOffset_Implementation() const
|
||||
{
|
||||
const float RandomX = UKismetMathLibrary::RandomFloatInRange(-DropRadius, DropRadius);
|
||||
const float RandomY = UKismetMathLibrary::RandomFloatInRange(-DropRadius, DropRadius);
|
||||
|
||||
return FVector(RandomX, RandomY, 0);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Drops/GIS_ItemDropperComponent.h"
|
||||
#include "GIS_InventoryTags.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GIS_InventorySystemComponent.h"
|
||||
#include "GIS_ItemCollection.h"
|
||||
#include "GIS_LogChannels.h"
|
||||
#include "Pickups/GIS_InventoryPickupComponent.h"
|
||||
#include "Pickups/GIS_ItemPickupComponent.h"
|
||||
#include "Pickups/GIS_WorldItemComponent.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_ItemDropperComponent)
|
||||
|
||||
void UGIS_ItemDropperComponent::Drop()
|
||||
{
|
||||
TArray<FGIS_ItemInfo> ItemsToDrop = GetItemsToDrop();
|
||||
DropItemsInternal(ItemsToDrop);
|
||||
}
|
||||
|
||||
void UGIS_ItemDropperComponent::BeginPlay()
|
||||
{
|
||||
if (!CollectionTag.IsValid())
|
||||
{
|
||||
CollectionTag = GIS_CollectionTags::Main;
|
||||
}
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
TArray<FGIS_ItemInfo> UGIS_ItemDropperComponent::GetItemsToDrop() const
|
||||
{
|
||||
return GetItemsToDropInternal();
|
||||
}
|
||||
|
||||
TArray<FGIS_ItemInfo> UGIS_ItemDropperComponent::GetItemsToDropInternal() const
|
||||
{
|
||||
TArray<FGIS_ItemInfo> Items;
|
||||
|
||||
UGIS_InventorySystemComponent* Inventory = UGIS_InventorySystemComponent::FindInventorySystemComponent(GetOwner());
|
||||
if (Inventory == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "requires inventory system component to drop items.")
|
||||
return Items;
|
||||
}
|
||||
UGIS_ItemCollection* Collection = Inventory->GetCollectionByTag(CollectionTag);
|
||||
if (Collection == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, " inventory missing collection with tag:%s'", *CollectionTag.ToString())
|
||||
return Items;
|
||||
}
|
||||
|
||||
Items = Collection->GetAllItemInfos();
|
||||
return Items;
|
||||
}
|
||||
|
||||
void UGIS_ItemDropperComponent::DropItemsInternal(const TArray<FGIS_ItemInfo>& ItemInfos)
|
||||
{
|
||||
if (bDropAsInventory)
|
||||
{
|
||||
DropInventoryPickup(ItemInfos);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 i = 0; i < ItemInfos.Num(); i++)
|
||||
{
|
||||
DropItemPickup(ItemInfos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGIS_ItemDropperComponent::DropInventoryPickup(const TArray<FGIS_ItemInfo>& ItemInfos)
|
||||
{
|
||||
if (AActor* PickupActor = CreatePickupActorInstance())
|
||||
{
|
||||
UGIS_InventorySystemComponent* Inventory = PickupActor->FindComponentByClass<UGIS_InventorySystemComponent>();
|
||||
UGIS_InventoryPickupComponent* Pickup = PickupActor->FindComponentByClass<UGIS_InventoryPickupComponent>();
|
||||
if (Inventory == nullptr || Pickup == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "Spawned pickup(%s) missing either inventory component or inventory pickup component.", *PickupActor->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
UGIS_ItemCollection* Collection = Inventory->GetDefaultCollection();
|
||||
if (Collection == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "Spawned pickup(%s)'s inventory doesn't have default collection.", *PickupActor->GetName());
|
||||
return;
|
||||
}
|
||||
Collection->RemoveAll();
|
||||
Collection->AddItems(ItemInfos);
|
||||
}
|
||||
}
|
||||
|
||||
void UGIS_ItemDropperComponent::DropItemPickup(const FGIS_ItemInfo& ItemInfo)
|
||||
{
|
||||
if (AActor* Pickup = CreatePickupActorInstance())
|
||||
{
|
||||
UGIS_ItemPickupComponent* ItemPickup = Pickup->FindComponentByClass<UGIS_ItemPickupComponent>();
|
||||
UGIS_WorldItemComponent* WorldItem = Pickup->FindComponentByClass<UGIS_WorldItemComponent>();
|
||||
if (ItemPickup == nullptr || WorldItem == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "Spawned pickup(%s) missing either ItemPickup component or WorldItem component.", *Pickup->GetName());
|
||||
}
|
||||
WorldItem->SetItemInfo(ItemInfo.Item, ItemInfo.Amount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Drops/GIS_RandomItemDropperComponent.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GIS_InventorySystemComponent.h"
|
||||
#include "GIS_ItemCollection.h"
|
||||
#include "GIS_LogChannels.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_RandomItemDropperComponent)
|
||||
|
||||
TArray<FGIS_ItemInfo> UGIS_RandomItemDropperComponent::GetItemsToDropInternal() const
|
||||
{
|
||||
TArray<FGIS_ItemInfo> Results;
|
||||
|
||||
UGIS_InventorySystemComponent* Inventory = UGIS_InventorySystemComponent::FindInventorySystemComponent(GetOwner());
|
||||
if (Inventory == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, "requires inventory system component to drop items.")
|
||||
return Results;
|
||||
}
|
||||
UGIS_ItemCollection* Collection = Inventory->GetCollectionByTag(CollectionTag);
|
||||
if (Collection == nullptr)
|
||||
{
|
||||
GIS_CLOG(Error, " inventory missing collection with tag:%s'", *CollectionTag.ToString())
|
||||
return Results;
|
||||
}
|
||||
|
||||
const TArray<FGIS_ItemStack>& ItemStacks = Collection->GetAllItemStacks();
|
||||
|
||||
TArray<FGIS_ItemInfo> ItemInfos;
|
||||
ItemInfos.Reserve(ItemStacks.Num());
|
||||
int32 ProbabilitySum = 0;
|
||||
|
||||
for (int32 i = 0; i < ItemStacks.Num(); ++i)
|
||||
{
|
||||
//加权
|
||||
ProbabilitySum += ItemStacks[i].Amount;
|
||||
ItemInfos[i] = FGIS_ItemInfo(ProbabilitySum, ItemStacks[i]);
|
||||
}
|
||||
|
||||
int32 RandomAmount = FMath::RandRange(MinAmount, MaxAmount + 1);
|
||||
Results.Empty();
|
||||
|
||||
for (int i = 0; i < RandomAmount; i++)
|
||||
{
|
||||
auto& selectedItemInfo = GetRandomItemInfo(ItemInfos, ProbabilitySum);
|
||||
bool foundMatch = false;
|
||||
//去重,多个栈可能指向同一个道具实例,若发现重复
|
||||
for (int j = 0; j < Results.Num(); j++)
|
||||
{
|
||||
if (Results[j].Item == selectedItemInfo.Item)
|
||||
{
|
||||
Results[j] = FGIS_ItemInfo(Results[j].Amount + 1, Results[j]);
|
||||
foundMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatch) { Results.Add(FGIS_ItemInfo(1, selectedItemInfo)); }
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
const FGIS_ItemInfo& UGIS_RandomItemDropperComponent::GetRandomItemInfo(const TArray<FGIS_ItemInfo>& ItemInfos, int32 ProbabilitySum) const
|
||||
{
|
||||
int32 RandomProbabilityIdx = FMath::RandRange(0, ProbabilitySum);
|
||||
|
||||
int32 min = 0;
|
||||
int32 max = ItemInfos.Num() - 1;
|
||||
int32 mid = 0;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
mid = (min + max) / 2;
|
||||
if (ItemInfos[mid].Amount == RandomProbabilityIdx)
|
||||
{
|
||||
++mid;
|
||||
break;
|
||||
}
|
||||
|
||||
if (RandomProbabilityIdx < ItemInfos[mid].Amount
|
||||
&& (mid == 0 || RandomProbabilityIdx > ItemInfos[mid - 1].Amount)) { break; }
|
||||
|
||||
if (RandomProbabilityIdx < ItemInfos[mid].Amount) { max = mid - 1; }
|
||||
else
|
||||
{
|
||||
min = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ItemInfos[mid];
|
||||
}
|
||||
Reference in New Issue
Block a user