I’m interested in how people setup their inventory systems.
I have Interactable Objects that contain a bunch of variables. When picking up an object, I could save these variables in a struct (name, image etc.) so I can show it in my inventory HUD. However, storing just some attributes won’t work because when I drop the object I need to spawn the Interactable Object itself.
Let’s say my player carries an Inventory Array where I can store my inventory. If I make that array an Actor Object Reference I can easily pull the attributes I need for my HUD as well as easily drop the item as I have an actor reference. However, if I’m referencing the Actor Object then it exists in the world. This means I have to hide it and have it follow the player (due to world partition I can’t leave it hidden somewhere on the map as it may get destroyed).
Ideally, I’d pickup the Interactable Object and store the class reference. That way I’m not carrying an instance of the object around, and then just spawn the object from class when dropped. However, with a class reference I can’t pull the attributes off of it as it’s not an object.
My current thinking is to combine the two… when my character picks up an object, it stores the neccessary attributes for my HUD etc. and then saves a reference to the class (all in a struct), then destroys the object. This way I have the attributes I need and the class ref so I can spawn a new object when I drop the item.
I typically use the same system that Lyra uses, which is to use replicated UObjects (or non-replicated if single player of course). This allows you to have a dynamic system which encases any type of item you need. With this method, you do not care about the data structure of each varying item type because the object itself handles it. If all items are not going to be derived from a base item class, interface functionality can be used to fill the gaps and get whatever data is needed regardless of the class. Now the rest is up to the implementer, but I generally attach the UObject holding the data to the actor. When it comes to equipping and using the item itself, I don’t actually spawn the actor in hand, but spoof it with just attaching the visual mesh to the player. The only time I would really spawn an actor is if I am dropping the item on the floor, or if it directly placed into the world as a pickup item. The reason being is SpawnActor is costly, and when I am spawning actors, I always use some form of optimization like pooling.
Edit: The only other caveat to this is in multiplayer, where a replicated UObject needs an Actor channel to replicate through. So when an Item Actor is destroyed with its UObject data, I generally just make a copy of the UObject to place in the inventory, making the new actor channel to use the player pawn rather than the Item Actor since it will be destroyed (and therefore wouldn’t allow the UObject to replicate properly).
It must be written in c++ and exposed to blueprints. The system changed in UE 5.1 I believe it was. There isn’t a lot you have to do, but it may be a little overwhelming at first if you haven’t dealt with replication in c++. Replicated Subobjects in Unreal Engine | Unreal Engine 5.1 Documentation gives you what you need, remember this is for 5.1+, earlier versions are a little different (there is documentation and some tutorials for this case online). The main two functions are ReplicateSubObjects through the actor (component) channel, and then to AddReplicatedSubObject. I put this into a component, but I also add a replicatedUObject class with some additional functionality like GetLifetimeReplicatedProps, CallRemoteFunction, GetFunctionCallspace. The latter two manage how the UObject should call its functions (local vs remote). There is a plugin in the marketplace for $4.99 that does all this for you as well. UObject Replication Plugin in Code Plugins - UE Marketplace