Inventory system - how to handle decaying items

How might you handle a situation like this:

You have items in your game that can be picked up by player and stored in inventory.

Most data about items can be got from a data table. But some variables might subject to continual change, like a “food spoilage” variable.

You might have a “Food” blueprint class that holds the “spoilage” logic.

For items that don’t have any logic like that, the only thing we need to do to transfer data about them from one place to another is some form of ID. Since all of the associated data is static, we can just lookup in a data table to get the values we need.

But if you need that food spoilage timer to keep decrementing the “spoilage” variable on a single food instance, then I think there is no choice - you have to actually keep an actor instance in the game and save/load that, right? Otherwise, how does the food spoilage logic keep running?

The simplest idea to come to mind is that, if player picked up an apple instance, for example, we’d just hide the static mesh and attach the apple actor to the player character, while also representing it in the inventory. It seems kinda stupid and literal, but how else do we keep the instances logic running?

I’ve heard of object pools. Is that the idea for a problem like this?

When you don’t need an actor to render an item, you should use a UObject. Structs are just for passing data, nothing more. UObjects are what you want to use when you need more than that, like a running background process or a simulation of something. Actors are UObjects but can do a lot more, things of which you don’t need in this situation. You don’t want to spawn 400 physical apples to run a simulation process.

2 Likes

An idea: You could store the game time it was picked up in the struct and update the status every time the player checks inventory / item or when sending to save game to store with updated status.

1 Like

I was thinking along similar lines after having time to sleep on this.

Initially I thougth I might have a manager class that holds all of the Uobjects in an array and then can run the simulation on them all at once (like every time game time has passed an hour, loop through array of uobjects with perishable tag), but I don’t suppose delegating things out to a manager class has any benefit versus just having the logic in the class.

And a composition approach wouldn’t work here because a uobject can’t hold components. So I think it has to be like, BasePickup_uobject, and then any special types of pickups would need their own instance.

I doubt there is much need for modularity because in a realistic survival game, it is known ahead of time what sort of behaviors each item might have. But suppose I wanted a composition approach - in that case the manager class could be an actor that holds all possible behavior components, and then each instance of the pickup_uobject can have a flag that tells which components it subscribes to?

Does that make sense? I might try setting it up as compositional just for curiosities sake, though I’m not sure it’s necessary.

yeah i like that idea! No reason to necessarily run a timer. We could just log game time when the item was picked up, and whenever it is made visible we can get the difference since the current game time and add that.

1 Like

Another question arises is that, when it comes to saving/loading or identifying a specific uobject, I think it may be necessary to use a unique identifier?

In that case, a new GUID should suffice? If i understand correctly it is guaranteed to always be unique?


I might be thinking too far ahead on that - perhaps there is no issue just to save the uobjects directly.

Some quick test using the Easy Multi Save system - I added 500 uobjects to an array and it’s saving and loading instantly, so I don’t think that will be a problem. Player would never have nearly that many objects in inventory. I am using the GUID just to make sure the objects are in fact unique.

But I think I won’t need the GUID unless I was making something like an object pool where I stored ID’s and associated structs as a way to avoid saving uobjects. But it seems that that won’t be necessary. I keep the idea written down in my wiki so I can use it if needed but i think just using uobjects like this to hold data is going to be sufficient.