-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
虚幻引擎 库存系统 inventory system #225
Labels
Unreal Engine
虚幻引擎
Comments
多人游戏库存系统此库存系统专为多人游戏设计,支持物品叠加以及服务器和客户端之间的同步。 物品被组织到插槽中,每个插槽都有叠加限制。如果达到限制,则会占用新的插槽; 物品的收集和消耗在服务器上进行管理,以确保一致性。 该系统还允许自定义物品收集条件。 首先创建将定义每个项目的类,在本例中为 PrimaryDataAsset。 #pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GFItemDefinition.generated.h"
/**
*
*/
UCLASS()
class GAMEPLAYFRAMEWORK_API UGF_PDA_ItemDefinition : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UFUNCTION(Blueprintable,BlueprintPure)
FORCEINLINE FName GetItemName() const {return ItemName; }
UFUNCTION(Blueprintable,BlueprintPure)
FORCEINLINE uint8 GetItemIndex() const {return ItemIndex; }
UFUNCTION(BlueprintCallable,BlueprintPure)
FORCEINLINE uint8 GetMaxStack() const {return MaxStack; }
private:
UPROPERTY(EditAnywhere,BlueprintReadOnly,meta=(AllowPrivateAccess = "true"))
FName ItemName;
UPROPERTY(EditAnywhere,BlueprintReadOnly,meta=(AllowPrivateAccess = "true"))
uint8 ItemIndex = 0;
UPROPERTY(EditAnywhere,BlueprintReadOnly,meta=(AllowPrivateAccess = "true"))
uint8 MaxStack = 1;
}; 现在,我们将创建将要存储的项目。它将是一个结构体 #pragma once
#include "CoreMinimal.h"
#include "Inventory/Item/PrimaryDataAsset/GFItemDefinition.h"
#include "FItem.generated.h"
USTRUCT(BlueprintType,Blueprintable)
struct FItem
{
GENERATED_BODY()
UPROPERTY(EditAnywhere,BlueprintReadWrite)
UGF_PDA_ItemDefinition* ItemDefinition;
UPROPERTY(EditAnywhere,BlueprintReadWrite)
uint8 Quantity;
bool operator==(const FItem& Other) const
{
return ItemDefinition->GetItemIndex() == Other.ItemDefinition->GetItemIndex();
}
}; 最后的步骤,创建将负责管理库存系统的 actor 组件。 #pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Inventory/Item/Struct/FItem.h"
#include "GFInventoryComponent.generated.h"
/*
* 基本规则
* 1:每个物品必须拥有唯一的ItemIndex。原因:结构中的比较基于其ItemIndex。
* 2:最大堆栈也代表您在某个槽中的最大数量(UI可视部分)。
* 如果您的堆栈达到最大值,则必须将新物品添加到库存中,依次占据其自己的槽。
* 3:如果您的物品栏达到最大值,您将无法再收集物品。
*/
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class GAMEPLAYFRAMEWORK_API UGF_InventoryComponent : public UActorComponent
{
GENERATED_BODY()
public:
UGF_InventoryComponent();
/** Functions *******************************************************************************************/
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
UFUNCTION(BlueprintCallable)
void AddInitialItems(const TArray<FItem>& InitialItems);
UFUNCTION(BlueprintCallable, Category = "Inventory")
virtual bool PickUpItem(const FItem& NewItem, uint8& Remaining);
UFUNCTION(BlueprintCallable, Category = "Inventory")
virtual void ConsumeItem(const uint8 ItemIndex, const uint8 Quantity);
protected:
UFUNCTION(Server,Reliable)
virtual void ServerAddOrStack(const FItem& ItemToAdd); //服务器尝试收集,因为它是正确的版本,它替换客户端版本并做出“安全”更正。
UFUNCTION(Server,Reliable)
virtual void ServerConsumeItem(const uint8 ItemIndex, const uint8 Quantity);
/** EndFunctions ****************************************************************************************/
/** Variables *******************************************************************************************/
protected:
UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Replicated,Category = "GameplayFramework|Inventory|Items")
TArray<FItem> Inventory;
UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Replicated,Category = "GameplayFramework|Inventory|Slots")
uint8 Slots = 10;
/** EndVariables ****************************************************************************************/
}; .cpp 文件 #include "Inventory/Component/GFInventoryComponent.h"
#include "Net/UnrealNetwork.h"
UGF_InventoryComponent::UGF_InventoryComponent()
{
PrimaryComponentTick.bCanEverTick = false;
SetIsReplicatedByDefault(true);
}
void UGF_InventoryComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(UGF_InventoryComponent, Inventory,COND_OwnerOnly)
DOREPLIFETIME_CONDITION(UGF_InventoryComponent, Slots,COND_OwnerOnly)
}
void UGF_InventoryComponent::AddInitialItems(const TArray<FItem>& InitialItems)
{
if (!GetOwner()->HasAuthority()) return;
for (const FItem& InitialITem : InitialItems)
{
uint8 Remaining;
PickUpItem(InitialITem,Remaining);
}
}
bool UGF_InventoryComponent::PickUpItem(const FItem& NewItem, uint8& Remaining)
{
if (!GetOwner()->HasAuthority())
{
ServerAddOrStack(NewItem);
}
uint8 RemainingStack = NewItem.Quantity;
for (FItem& ItemData : Inventory)
{
if (ItemData.ItemDefinition->GetItemIndex() == NewItem.ItemDefinition->GetItemIndex() && ItemData.Quantity < ItemData.ItemDefinition->GetMaxStack())
{
const uint8 StackSpace = ItemData.ItemDefinition->GetMaxStack() - ItemData.Quantity;
const uint8 ValueToAdd = FMath::Min(StackSpace, RemainingStack);
ItemData.Quantity += ValueToAdd;
RemainingStack -= ValueToAdd;
if (RemainingStack == 0)
{
Remaining = 0;
return true;
}
}
}
while (RemainingStack > 0 && Inventory.Num() < Slots)
{
const uint8 ValueToAdd = FMath::Min(NewItem.ItemDefinition->GetMaxStack(), RemainingStack);
Inventory.Emplace(NewItem.ItemDefinition, ValueToAdd);
RemainingStack -= ValueToAdd;
}
Remaining = RemainingStack;
return RemainingStack == 0;
}
void UGF_InventoryComponent::ServerAddOrStack_Implementation(const FItem& ItemToAdd)
{
uint8 Remaining;
PickUpItem(ItemToAdd,Remaining);
}
void UGF_InventoryComponent::ConsumeItem(const uint8 ItemIndex, const uint8 Quantity)
{
if (!GetOwner()->HasAuthority())
{
ServerConsumeItem(ItemIndex,Quantity);
}
uint8 RemainingQuantity = Quantity;
for (int32 i = Inventory.Num() - 1; i >= 0; --i)
{
FItem& ConsumeItem = Inventory[i];
if (ConsumeItem.ItemDefinition->GetItemIndex() == ItemIndex)
{
if (ConsumeItem.Quantity > RemainingQuantity)
{
ConsumeItem.Quantity -= RemainingQuantity;
return;
}
RemainingQuantity -= ConsumeItem.Quantity;
Inventory.RemoveAt(i);
}
if (RemainingQuantity == 0) break;
}
}
void UGF_InventoryComponent::ServerConsumeItem_Implementation(const uint8 ItemIndex, const uint8 Quantity)
{
ConsumeItem(ItemIndex,Quantity);
}
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
虚幻引擎 库存系统 inventory system
The text was updated successfully, but these errors were encountered: