Store Blueprint actor in a TArray C++

I am trying to create an Inventory system in c++ which allows me to store a blueprint derived from a base class of APickup(C++ Class). My problem is I am struggling to find a way to Check if the pickup blueprint is a derivative of APickup. Here is my attempted code.

//BASECHARACTER.CPP

void ABaseCharacter::Interact()
{
	if (LastSeenInteractable) // Current linetrace hit (Working)
	{
		if (Inventory) //Check to see if the Character has an Inventory
		{
                    // Chek to see if the item is derived from APickup and assign it to 
		if (APickup* PickupToAdd = Cast<APickup>(LastSeenInteractable))
		{
			Inventory->AddToInventory(PickupToAdd);
		}
		}
		LastSeenInteractable->Interact_Implementation();
	}
}


//INVENTORY.CPP
void UCustomInventory::AddToInventory(APickup* PickupToAdd)
{
		PickupArray.Add(PickupToAdd);
}

//INVENTORY.H
TArray<class APickup*> PickupArray;

Does this seem right? I’ve logged a loop of the array and it does indeed add something to it, but this would just be a pointer to the initial object from my understanding. I have tried a few things but I’m unable to spawn the object from the array that I have created, Any help would be greatly appreciated. Specifically an explanation of how to store the blueprint that is picked up in an array. Thanks in advance.

EDIT:
Ok this works but I want to be able to destroy the actor on pickup and respawn it when the player uses my EquipPickup function. If i set the item to be destroyed on pick up after adding it to the array I will be left with a null pointer so really I want to move or copy the actor in to the array so I can bring it in to other levels.

A pointer, by definition, is used to avoid making extraneous copies of an object. If you wanted to store a copy, your array would need to be:

TArray<class APickup> PickupArray;

Which would store an entire copy of the object, rather than just a pointer to it. That said, I don’t think you really want to destroy the object/store a copy. If I understand you correctly, you just want to hide it after it’s been picked up. In which case you could just call

PickupToAdd->SetActorHiddenInGame(true);

That way you aren’t duplicating Actor objects (which is pretty expensive and honestly I’m not sure if that would work), you still only store pointers in your array, and as long as your array is a UPROPERTY then it should all transfer between levels seamlessly.

Hi thanks for your response.

I had a play around with my code and found a way of doing what I wanted. I did try to store a copy in the array but I couldn’t get the object Stored in the array from the pointer. Maybe I just spent too long on it. I did however use the for my array and then used what was stored in the array to spawn a new actor to the socket on the player.

I did it this way because I wanted to be able to have lets say 100 of the same object. Surely having all those objects stored in memory would become an issue?

My current setup works as intended but I’m currently unable to store the parameters of the object collected and spawn the new one with the same ones. Any insight? Thanks again.

You could always have some light weight structure that describes the object (name, stats, or whatever else could be different between objects), rather than the actual object itself. Then when you need to, you instantiate the full object, set the values using your light weight structure, and go from there.

Yeah just been trying to read up on that now. Too be honest I am completely lost on where to start with it. Like where to declare said struct and how to instantiate the full object and set the values. Don’t suppose you could soon feed me an example?

You can declare the struct where ever you declare APickup, assuming your pickups all inherit from APickup, you could do something like

USTRUCT()
struct FItemInfo
{
 GENERATED_USTRUCT_BODY()

  TSubClassOf<APickup> ItemClass;
  // Whatever else you need to store to 
}

// Your inventory would then have
TArray<FItemInfo> MyInventory;

Then you could have some method in your Inventory called something like:

APickup* UCustomInventory::InstantiatePickup(FItemInfo& InItemInfo)
{
    APickup* Item = NewObject<APickup>(InItemInfo.ItemClass);
   // Set any other properties you need to on "Item"
   return Item;
}

Yeah my APickup class is my abstract class that all pickups are derived from.

So I could store what material, value and mesh the item has in the struct, before I call the destroy function? I always thought a STRUCT was just a class but its members just defaulted to public instead of private?

So I would store my item structs in the array if I understand correctly? Would you know the difference between:

GetWorld()->SpawnActor(PickupToEquip);

and

APickup* Item = NewObject(InItemInfo.ItemClass);

(Besides the obvious params; Mainly difference between spawning and and calling NewObject)

A struct is just an object, just like a class. Just make sure you are only storing what you need to. For example if you have a flashlight class (AFlashlight) that inherits from APickup, and all flashlights use the same mesh, etc. Then just storing the class type is enough.

And yea, since you are using Actors instead of UObjects you would need to use SpawnActor, but you can use it the same way:

GetWorld()->SpawnActor(InItemInfo.ItemClass)

Ah I think I get it. I will put sometime into it and if I can’t get it working I will be back to pick your brain. Thanks for your help and time Matt!

Just wanted to report back and say I got it working in the end. Had a slight hiccup where I put my function to store the items info in my constructor. Didn’t realise it would never be called on the blueprint. Solved it in the end by moving it to BeginPlay. Thanks again for your help buddy!