UE4 | Inventory for Multiplayer # 4 | Creating and connecting a container

  • Tutorial

In this article, we will discuss creating an inventory component and connecting it to the required Actor. Since this component is simply a repository of items and the logic of their loading / unloading, there is no difference in applying it to a character or any box.


You can create a component using either Blueprint , or C through C ++ . I prefer the second method, as I am going to actively use the C ++ functionality .




First of all, we create a cell structure for storing one item. I prefer to store it in a separate .h file in order to be free to connect as needed where needed:


StructContainerStack.h
/// Copyright 2018 Dreampax Games, Inc. All Rights Reserved./* Struct for Container Stack. This file is used as #include */#pragma once/* Includes from Engine */#include"GameplayTagContainer.h"/* Includes from Dreampax */#include"Data/StructItemFactors.h"#include"StructContainerStack.generated.h"/* Declaration for contaiter stack structure. BlueprintType required to use in BP */
USTRUCT(BlueprintType)
structFContainerStack
{
    GENERATED_USTRUCT_BODY()
    /* Gameplay tag to store the name */
    UPROPERTY(EditAnywhere)
    FGameplayTag ItemNameTag;
    UPROPERTY(EditAnywhere)
    int ItemAmount;
    /* Specific factors such as durability, damage etc. */
    UPROPERTY(EditAnywhere)
    TArray <FItemFactor> ItemFactors;
    FContainerStack()
    {
        Clear();
    }
    voidClear(){
        ItemNameTag.FromExportString("NAME_None");
        ItemAmount = 0;
        ItemFactors.Empty();
    }
    FORCEINLINE FGameplayTag GetItemNameTag()const{
        return ItemNameTag;
    }
    voidSetItemNameTag(FGameplayTag const & ItemNameTagNew){
        if (ItemNameTagNew.IsValid())
        {
            ItemNameTag = ItemNameTagNew;
        }
        else
        {
            Clear();
        }
    }
    FORCEINLINE intGetItemAmount()const{
        return ItemAmount;
    }
    voidSetItemAmount(intconst & ItemAmountNew){
        if (ItemAmountNew > 0)
        {
            ItemAmount = ItemAmountNew;
        }
        else
        {
            Clear();
        }
    }
    FORCEINLINE TArray<FItemFactor> * GetItemFactors()
    {
        return &ItemFactors;
    }
    voidSetItemFactors(TArray<FItemFactor> const & ItemFactorsNew){
        if (ItemFactorsNew.Num() > 0)
        {
            ItemFactors = ItemFactorsNew;
        }
    }
};

Yes, our inventory cell contains only 3 variables: ID, quantity and unique parameters. Nothing extra. All data can be copied, saved and downloaded without problems. No textures, references to Actors , etc. not here. All additional information can be downloaded from the database to DataAsset , which we talked about earlier.


Most likely, you have already paid attention to another StructItemFactors.h structure , connected at the beginning. It is nothing but a repository of any unique properties of the object (in the form of a float ), such as wear, damage, etc. That is, the properties that are inherent only in this copy of the object, and no other is the same. This structure is very simple:


StructItemFactors.h
/// Copyright 2018 Dreampax Games, Inc. All Rights Reserved./* Struct for Factors. This file is used as #include */#pragma once/* Includes from Engine */#include"GameplayTagContainer.h"/* Includes from Dreampax */// no includes#include"StructItemFactors.generated.h"
USTRUCT(BlueprintType)
structFItemFactor
{
    GENERATED_USTRUCT_BODY()
    /* Name of Item Attribute Factor */
    UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase")
    FGameplayTag ItemFactorTag;
    /* Factor for the Item Attribute */
    UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase")
    float ItemFactor;
    /* for this type to be comparable */friendbooloperator==(const FItemFactor & Lhs, const FItemFactor & Rhs)
    {
        return Lhs.ItemFactorTag == Rhs.ItemFactorTag && Lhs.ItemFactor == Rhs.ItemFactor;
    }
    FItemFactor()
    {
        Clear();
    }
    voidClear(){
        ItemFactorTag.EmptyTag;
        ItemFactor = 0;
    }
    FORCEINLINE FGameplayTag GetItemFactorTag(){
        return ItemFactorTag;
    }
    voidSetItemFactorTag(FGameplayTag const &ItemFactorTagNew){
        if (ItemFactorTagNew.IsValid())
        {
            ItemFactorTag = ItemFactorTagNew;
        }
        else
        {
            Clear();
        }
    }
    FORCEINLINE floatGetItemFactor(){
        return ItemFactor;
    }
    voidSetItemFactor(floatconst & ItemFactorNew){
        if (ItemFactorNew > 0.0f)
        {
            ItemFactor = ItemFactorNew;
        }
        else
        {
            Clear();
        }
    }
};

It is worth noting one very interesting function in the structure above, which is designed to significantly simplify our lives:


friendbooloperator==(const FItemFactor & Lhs, const FItemFactor & Rhs)
    {
        return Lhs.ItemFactorTag == Rhs.ItemFactorTag && Lhs.ItemFactor == Rhs.ItemFactor;
    }

This is nothing more than the comparison operator == , which we can use for this structure, so as not to extract elements for this every time. Very comfortably.




So, with the structures finished. We proceed to the creation of the component:


DreampaxContainerComponent.h
/// Copyright 2018 Dreampax Games, Inc. All Rights Reserved.#pragma once/* Includes from Engine */#include"Components/ActorComponent.h"#include"GameplayTagContainer.h"/* Includes from Dreampax */#include"Data/StructItemFactors.h"#include"Data/StructContainerStack.h"#include"DreampaxContainerComponent.generated.h"//UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) // currently not required
UCLASS()
classDREAMPAX_APIUDreampaxContainerComponent :public UActorComponent
{
    GENERATED_BODY()
private:
    UPROPERTY(Transient, Replicated, EditAnywhere, Category = "Container")
    TArray<FContainerStack> ContentOfContainer;
public:
    /* Sets default values for this component's properties */
    UDreampaxContainerComponent(const FObjectInitializer & ObjectInitializer);
    /*
    Далее идут функции для получения данных из компонента,
репликации и т.п..
    */
};

If in the code above activate the line


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )

then you can connect this component directly to Blueprint . I prefer to do this in C ++ . For Character, it looks like this:


Inventory = CreateDefaultSubobject<UDreampaxContainerComponent>(TEXT("Inventory"));

Well, for some chest like this:


ADreampaxActorContainer::ADreampaxActorContainer(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    Container = CreateDefaultSubobject<UDreampaxContainerComponent>(TEXT("Container"));
}

As you can see, the difference is only in the names of variables.




In the next article I will talk about the features of replication (simple on the fingers ), which will make our inventory truly multiplayer.


Also popular now: