After finally getting my own inventory system working id figure it would be a good idea to lend back the hand to the community so, Lets begin!
First we need an actor that will serve as our item
Item Header
UCLASS()
class AProojectItem : public AActor
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Item)
FString ItemName;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Item)
int32 Value;
UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "Item: Used"))
virtual void Used();
UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "Item: Dropped"))
virtual void Dropped();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Item)
TSubobjectPtr<class UStaticMeshComponent> Mesh;
virtual void BeginPlay() OVERRIDE;
void PickedUp();
};
I used BlueprintImplementableEvent in the Used & Dropped functions so i could override these from a blueprint, since my items are blueprints i dont need to create a function in c++ for each one i just declare it on its blueprint
Item.cpp
AProojectItem::AProojectItem(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
Mesh = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("Mesh"));
RootComponent = Mesh;
}
void AProojectItem::BeginPlay()
{
Super::BeginPlay();
Mesh->SetSimulatePhysics(true);
Mesh->WakeRigidBody();
}
void AProojectItem::PickedUp()
{
if (Mesh)
{
Mesh->DestroyComponent(); // physical item has been picked up, destroy its visible component
}
}
Now that we have our item actor we need an array to store these into
Character Header
UCLASS(config=Game)
class AProojectCharacter : public ACharacter
{
UPROPERTY(EditAnywhere, Category = Inventory)
TArray<class AProojectItem*> ItemInventory; // Our Inventory
virtual void Tick(float DeltaSeconds) OVERRIDE;
void PickUpItem(AProojectItem* Item);
};
Now that we have the array the only thing we need to do is a get a pointer to the spawned item and add it to the array , for this i just do a trace each tick and check if its an Item class
#include "ProojectItem.h"
void AProojectCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
FVector CamLoc;
FRotator CamRot;
Controller->GetPlayerViewPoint(CamLoc, CamRot); // Get the camera position and rotation
const FVector StartTrace = CamLoc; // trace start is the camera location
const FVector Direction = CamRot.Vector();
const FVector EndTrace = StartTrace + Direction * 200;
// Perform trace to retrieve hit info
FCollisionQueryParams TraceParams(FName(TEXT("WeaponTrace")), true, this);
TraceParams.bTraceAsyncScene = true;
TraceParams.bReturnPhysicalMaterial = true;
FHitResult Hit(ForceInit);
if (GetWorld()->LineTraceSingle(Hit, StartTrace, EndTrace, ECC_WorldStatic, TraceParams))
{
AProojectItem* NewItem = Cast<AProojectItem>(Hit.GetActor()); // typecast to the item class to the hit actor
if (bDrawDebugViewTrace)
{
DrawDebugLine(
GetWorld(),
StartTrace,
EndTrace,
FColor(255, 0, 0),
false,
3,
0,
1
);
}
if (NewItem) // if we hit an item with the trace
{
this->PickUpItem(NewItem); // pick it up
}
}
}
void AProojectCharacter::PickUpItem(AProojectItem* Item)
{
if (Item)
{
ItemInventory.Add(Item); // add it to the array
Item->PickedUp(); // hide mesh
}
}
By the end you should have someting like this
Remember to call the Used & Dropped events somewhere in c++ so they can be used in the blueprint!
Hope someone finds this useful