Skip to content

Custom logic for item combination

FreemanMakesGames edited this page Sep 2, 2020 · 11 revisions

FMGInvSys supports custom logic for item combination. In this article we'll take the demo video here as an example, where combining two cubes of different types destroys both, and combining two cubes of same type returns a cylinder.

C++ item core

To have custom logic when combining cubes, we need to first create a C++ subclass of UFMGInvSysItemCore, then create a blueprint subclass of the C++ subclass. Let's assume they are named UCubeCore and BP_CubeCore.

UCubeCore can be simple:

UCLASS()
class FMGINVSYSDOCS_API UCubeCore : public UFMGInvSysItemCore
{
	GENERATED_BODY()

public:

	UFUNCTION( BlueprintCallable )
	FString GetCubeType() const { return CubeType; }

	UFUNCTION( BlueprintCallable )
	void SetCubeType( FString InCubeType ) { CubeType = InCubeType; }
	
protected:

	FString CubeType;
	
};

(For it to work in multiplayer, simply replicate CubeType.)

Function mapping in item combiner

An item combination with custom logic works by mapping the array of source item classes, to a delegate whose function returns the combination result. For this, we need to create a C++ item combiner. I'll leave the demonstration to the code itself.

ItemCombiner.h

UCLASS()
class FMGINVSYSDOCS_API AItemCombiner : public AFMGInvSysItemCombiner
{
	GENERATED_BODY()

protected:

	virtual void BeginPlay() override;

protected:

	FFMGInvSysCombineDelegate CombineTwoCubesDelegate;

protected:

	UPROPERTY( EditDefaultsOnly )
	TSubclassOf<UFMGInvSysItemCore> CubeCoreClass;

	UPROPERTY( EditDefaultsOnly )
	TSubclassOf<UFMGInvSysItemCore> CylinderCoreClass;

protected:

	FFMGInvSysCombineResult CombineTwoCubes( TArray<UFMGInvSysItemCore*> SourceItemCores );
	
};

ItemCombiner.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ItemCombiner.h"

#include "../Items/CubeCore.h"

void AItemCombiner::BeginPlay()
{
    Super::BeginPlay();

    FFMGInvSysItemCoreClassArray Source;
    Source.ItemCoreClasses.Add( CubeCoreClass );
    Source.ItemCoreClasses.Add( CubeCoreClass );
    CombineTwoCubesDelegate.BindUObject( this, &AItemCombiner::CombineTwoCubes );
    FunctionMap.Add( Source, CombineTwoCubesDelegate );
}

FFMGInvSysCombineResult AItemCombiner::CombineTwoCubes( TArray<UFMGInvSysItemCore*> SourceItemCores )
{
    FFMGInvSysCombineResult Result;

    UCubeCore* CubeCore0 = Cast<UCubeCore>( SourceItemCores[ 0 ] );
    UCubeCore* CubeCore1 = Cast<UCubeCore>( SourceItemCores[ 1 ] );

    if ( CubeCore0->GetCubeType() == CubeCore1->GetCubeType() )
    {
        Result.ResultItems.Add( NewObject<UFMGInvSysItemCore>( this, CylinderCoreClass ) );
    }
    else
    {
        // By doing nothing here, Result.ResultItems will be empty,
        // So character will destroy the source cubes, but add nothing new.
    }

    Result.Successful = true;

    return Result;
}

Since an item core is a UObject and can't be directly placed in the level, we can initialize the cube core's cube type from its actor wrapper BP_Cube. In the blueprint editor, give BP_Cube a string variable CubeType, and set "Instance Editable" to be true. The initialization is trivial: https://blueprintue.com/blueprint/foh4-800/

All that's left to do is placing a BP_Cube in the level, and set its Cube Type in the Details panel.


Beware that in a case where source item cores are of different classes, it needs slightly more work in the combine function. You'll likely need a for-loop that traverses through the source array, and use IsA to find out which item core is of what class.