Inventory/Item system

So i’ve been trying for a while now to figure out a good item system for my game. I thought I found a solution by using GameObjects as items, since it checked all of my requirements:

  • The item needs to be visible when equipped (I just position the GameObject to the correct slot)
  • The item needs to be an instance, that is, have unique values such as durability and other fields specific to certain items
  • It needs to have a pickup with proper colliders. That is, the colliders should match the shape of the item.
  • Weapons will have trigger colliders that will define the hitbox of that weapon. For example, a sword would have a box collider covering the entirety of the blade.
  • Some items will have unique animations.
  • Items will be usable, and even have unique behaviours while equipped. (Such as balloons lowering your gravity)

The way I’m doing it now, is I have a public class Item : MonoBehaviour, IInteractable attached to a GameObject, where I define the behaviour of the item, and then a public class ItemData : ScriptableObject where I keep the name, description, stats, etc. This works fine, and allows me to easily make items with unique behaviours, animations etc, since I’m just working with a normal GameObject, and it fulfills every requirement on the list.

But, I don’t like this approach since it creates a lot of problems when handling it in the inventory. Here are a few examples:

  • When picking up the item, I need to disable all colliders and rigidbody, and when dropped re-enable them. This just feels very hacky.
  • Every slot has two fields: Item and Amount. When I have, let’s say 10 of an Item in a slot, there is really only one instance of that item. But when I need to split it into multiple slots, I need to create a new instance for every slot, and when put back together, I need to destroy any extra instances. Doing this often could lead to performance issues I think.
  • Since the item is both the pickup and the item, I can’t have an item pickup that gives you x amount of that item.
  • Using prefabs to store items is a bit of a pain

Ideally I’d want to have ItemData scriptable object and Item class to define behaviour. Then have some sort of visual representation of that object in the world. But then I wouldn’t have two of my requirements: Animations, and the colliders.

I’ve searched and searched but I can’t find anything that suits my needs, which leads me to believe maybe I should rethink what my necessities should be. But I still wouldn’t really know what the best way of doing an inventory system would be.

Can someone smarter/with more experience than me guide me a bit on what I should be doing? Should I keep using GameObjects as items, should I use normal classes? Or should I rethink everything?

1 Like

I think you’re forgetting scriptable objects can reference prefabs. Problem solved. The prefab has all the colliders, etc, and can just be instanced from the reference to the scriptable object.

In any case, using game objects for inventories is not a good idea, as you’re right to think. Games like Subnautica went with that path and they were worse off because of it (though the code production of that game seemed to have been mostly out-sourced). An inventory can effectively live in the plain C# world, though scriptable objects are useful for authoring data, such as for the items themselves, inventory objects, etc.

Unique values are handled by having a class that wraps around the item SO itself, and acts as an intermediary. Most if not all ‘gameplay’ use of items should be through this instance wrapper.

I highly recommend reading up on [SerializeReference] and tools that let you make use of it (such as Odin Inspector). Being able to serialised plain C# classes with polymorphism is invaluable, and will save you from having a messy inheritance heirarchy or tons of boilerplate with interfaces. Eg, you can often work with just one item class, and use SerializeReference to outline ‘item components’ that are serialised into a collection, that define all the behaviour of an item.

Also make sure you think about how to save and load these earlier rather than latter. In any case, make a test project and play around with ideas on a small scale. This kinda stuff is going to put you through the wringer with C# more so than Unity, so expect to revise and refactor a lot.

1 Like

I see, so the structure would look something like this:
ScriptableObject for data
Class for behaviour
Prefab for visual respresentation

So when I equip the item into visible slot, I instantiate the prefab. But I’m still seeing a few problems:

  • The pickup has physics, while it shouldn’t in the inventory. Which means I either have two prefabs: one for the pickup, and one for the item, or I disable the physics for when it’s in the inventory.
  • How would I communicate the TriggerEnter from the gameobject to my plain c# class?

I’ll read up more on SerializeReference.

Just turn the rigidbody/colliders off. It’s literally just a few lines of code.

Via code? I can’t tell you how to do everything here. How you set up a combat system is entirely up to you to engineer it, and it’s not that complicated to get a trigger collider to fire off an event to anything that’s listening.

Don’t overthink this too much. Spend more time coding than thinking about it. Remember an item/inventory system is going to live more in the pure C# world than it is in the Unity world.

Yeah, you’re right, I should just start doing it and things will fall into place. Thanks for the help

This is the typical issue from not separating data or “the thing” from its visuals.

The pickup should be a pickup, not the thing itself. It should contain the ID of the thing it’s representing (or reference to ScriptableObject). If you want to edit it by hand it should be a prefab. It disappears/destroys when “picked up”.

3 Likes

Yes, an unfortunately all-too-common problem given how quick and easy it is to throw piles of wonderful connected things together in Unity until you have a stringy gooey mess of MonoBehaviours everywhere!

I love it, I do it all the time, but it can be a bit of a siren’s call if you don’t resist. I have refactored SO much code to make it not be this way after a super-hasty crazy-fast gamejam session. :slight_smile:

Meanwhile, for OP, let me give you a framework to think about your problem space more clearly, to hopefully allow you to attack it in small digestible pieces until it is all unkinked and working for you:

These things (inventory, shop systems, character customization, dialog tree systems, crafting, etc) are fairly tricky hairy beasts, definitely deep in advanced coding territory.

Inventory code never lives “all by itself.” All inventory code is EXTREMELY tightly bound to prefabs and/or assets used to display and present and control the inventory. Problems and solutions must consider both code and assets as well as scene / prefab setup and connectivity.

Inventories / shop systems / character selectors all contain elements of:

  • a database of items that you may possibly possess / equip
  • a database of the items that you actually possess / equip currently
  • perhaps another database of your “storage” area at home base?
  • persistence of this information to storage between game runs
  • presentation of the inventory to the user (may have to scale and grow, overlay parts, clothing, etc)
  • interaction with items in the inventory or on the character or in the home base storage area
  • interaction with the world to get items in and out
  • dependence on asset definition (images, etc.) for presentation

Just the design choices of such a system can have a lot of complicating confounding issues, such as:

  • can you have multiple items? Is there a limit?
  • if there is an item limit, what is it? Total count? Weight? Size? Something else?
  • are those items shown individually or do they stack?
  • are coins / gems stacked but other stuff isn’t stacked?
  • do items have detailed data shown (durability, rarity, damage, etc.)?
  • can users combine items to make new items? How? Limits? Results? Messages of success/failure?
  • can users substantially modify items with other things like spells, gems, sockets, etc.?
  • does a worn-out item (shovel) become something else (like a stick) when the item wears out fully?
  • etc.

Your best bet is probably to write down exactly what you want feature-wise. It may be useful to get very familiar with an existing game so you have an actual example of each feature in action.

Once you have decided a baseline design, fully work through two or three different inventory tutorials on Youtube, perhaps even for the game example you have chosen above.

Breaking down a large problem such as inventory:

https://discussions.unity.com/t/826141/4

If you want to see most of the steps involved, make a “micro inventory” in your game, something whereby the player can have (or not have) a single item, and display that item in the UI, and let the user select that item and do things with it (take, drop, use, wear, eat, sell, buy, etc.).

Everything you learn doing that “micro inventory” of one item will apply when you have any larger more complex inventory, and it will give you a feel for what you are dealing with.

Breaking down large problems in general:

https://discussions.unity.com/t/908126/3

1 Like

Hey kurt-dekker! Thanks so much for responding to this thread, i’ve seen you in many other threads dealing with inventory problems and you’ve been very helpful in figuring out what I need.
The inventory part is the part I sort of already have figured out, in fact I have a pretty good inventory/slot system with UI, and since most of it is abstracted I can just reuse it. The thing I need to figure out now is how to communicate my plain c# item class with things such as the item’s model and scripts that it may contain, since for example, a weapon will have a “Weapon” script that will handle TriggerEnter and such. But that’s for me to figure out. I’ll start small like you said and scale from there.

Oh and since I’ll be using inheritance for different item behaviours I guess I need to link the ItemData with some type. I think I’ll use generics for that:
ItemData<T> : ScriptableObject where T : Item
and same for the item
Item<T> where T : ItemData<Item>
Now that i’m writing it out it seems kinda messy, but I can’t think of any other way to get the correct Item class from the ItemData

No don’t use generics here. You code will look like hell. This also means you can’t have a collection of different types of Items or ItemData, so you can throw the advantages of polymorphism out the door.

The relationship should be one way. The item scriptable objects just hold data. That’s all they do. They don’t ‘do’ anything, they don’t talk to anything, just hold data. Other things can reference this data to know of the immutable information about an item, but the item itself has zero care about anything outside.

The plain C# Item wrapper stores a reference to the item asset and represents a ‘live’ item in the game world. All information about the item is routed through the wrapper; and it probably shouldn’t even expose the actual item directly in any way. The wrapper contains all mutable information about an item, such as durability, ammo, etc.

This is what I was getting at with SerializeReference. No need for making tons of item classes with inheritance. You just need the one class, and you can serialise in different plain C# classes into a collection with polymorphism to mix and match behaviour. Kinda looks like this in a shelved project of mine:

(Odin Inspector is doing the magic here).

While this looks very cool, i’d like to go for a (free) and more traditional approach

Although, I do think it’d be interesting to use a component based system for items instead of inheritance

Personally, I wouldn’t know how to get much control of an inventory system without heavy use of game objects.
9107785--1262890--ezgif.com-optimize.gif

Game Objects are just part what’s going on the ‘physical’ world, which is should be backed by a large degree of data not tied to any Unity objects.

An inventory UI, whether its uGUI or UI Toolkit, should just be displaying and shuffling around data. If your inventory is actually represented by game objects and their hierarchy… that’s just making life very, very hard on yourself.

1 Like

Originally, the inventory was going to be pure c#. But I couldn’t figure out how to display swapping items in UI.

Now it’s a forloop that checks 5 squares, that checks if a item is inside the square.
These items are instantiated and destroyed when picking up/dropping items.

While it does feel fragile, all interactions (changing/reading) with the inventory are done with methods and as Todd Howard used to say “It just works”

These are two completely separate layers of design here. The user interface handles the input and tells the data layer what to do. It’s not particularly hard to move things around in a regular List<T>.

Inventories are like ogres, they have layers.

2 Likes

It’s the moving, displaying or not displaying UI that I’m currently struggling with.

An inventory separate from UI would probably be something I could achieve 5 years later.

With my current inventory accessing or changing something requires a simple method. So the bulky code is out of sight.

The way I went about the Inventory’s UI is that each slot has an event OnSlotUpdate, and each UI slot just subscribes to that and updates its text and icon whenever the event is fired. If you want to interact with your inventory, all you have to do is access the inventory (for example when a UI slot is clicked), and do whatever you want with it, since it will update automatically through the subscribed events. That way you have an inventory system that works by itself, and a UI that simply accesses the inventory

1 Like

So I’m a bit embarrased to say this, but I’m stuck (again). I finally implemented the item system after much overthinking, and it works! This is a quick rundown of how I implemented it:

I separated items into data and instance:

  • ItemData (the item’s definition, scriptable object): It contains data such as name, description, stats and stat modifiers, and components. It holds reference to the item’s pickup and model prefabs. It defines the item.
  • Item (the item’s instance, c# class): It wraps the ItemData and instantiates its values, making a copy of the components and initializing them. This is the actual item in the game.

So, as you can see I took inspiration from spiney and used components to define item’s behaviour. The thing is, since I’m going completely C# here I can’t take advantage of unity’s built-in Monobehaviours, so to solve this I created my own GameObject Component system, I called it “ModuleObject” and “Modules”. Each ModuleObject has a list of Modules, and the ModuleObject calls upon the Modules’ methods. So: ModuleObject.Update() → List.Update(). And, I mean it does work, but I feel like I wayyyy over-engineered this. I mean sure, this is how I’d do it without working with unity, I’d probably create my own ECS and go from there, but this is Unity we’re talking about, it already has a GameObject Component system that I should be taking advantage of. It just feels a bit redundant to re-implement something that’s already implemented. The reason why I made this whole system in the first place is because while in an inventory, the item is really nothing but data. It doesn’t have a representation in the world, but it still has to have all its instance data and all its components.

Am I overcomplicating things? I’d really just like to know what different approaches people have used for their items, since tutorials on youtube are always very half-baked and never really implement item behaviour.

So you didn’t want to use the MonoBehaviour / Component system, in use by millions of people and tried and tested and understood and documented in literally millions of documents all over the web, example code, etc.

And you wrote your own?

Yes.

You must be confused about the purpose of tutorials. They’re not to give you a final product. That’s not a thing. The point of a good tutorial is to teach one thing (or a small subset of related things) in the clearest simplest un-cluttered straightforward way possible. The point is for YOU to learn everything necessary to take the principles in the tutorial and use them to engineer your own solution.

This is software engineering after all.

Did you even consider any of the many points, which WILL apply whether you consider them or not, in my original reply about inventories??

The engineering problems of making an inventory are complex and interconnected. My post is simply to help you reason about them in a systematic approach so that you can engineer a solution suitable to your needs. Remember, the minecraft inventory wouldn’t work in skyrim, and vice-versa.