How to make the Inventory accept only a certain type of items

After following the Making Inventory Containers (Banks, NPC loots, Treasure Chests) post, I tried to make it so that I could have certain Inventories that could only accept a certain type of items.

I gave this a try by adding adding simple bool in my Inventory.cs script, like isToolbox. I then went to the AddToFirstEmptySlot and AddItemToSlot methods and I simply copied what was already inside, added an if statement for if (isToolbox) and pasted the logic in there. Also, before that I made sore that i also added a check for if the item is of type Tool. So far so good.

Next I added an else inside, to handle items that are not of that type, and I simply just did a RemoveItem() and AddToFirstEmptySlot() after, the AddToFirstEmptySlot is pointing to my Players inventory, so it would know where exactly to put it.

When I went ahead and tested it, it actually worked. But my issue is that, it kind of seems to have some kind of major impact on the game performance. What I mean is, after using the Profiler, I saw that each time, even while in my own player inventory, when I do a simple item drag and drop, there is a spike in performance, where for a split second, the frames drop by ~20-30, and it’s like a micro stutter that you can’t really see it. you can notice it if for example you have a particle effect playing somewhere on the map, and you can see the animation skipping for that split second. I saw that the spike comes from the face that the game has to Instantiate and do a bunch of other things when you perform that action.

Now my biggest problem comes when I start moving items in that “Toolbox” container. If I move one item in, it’s ok, but if I start putting more items in, it will make the game stutter really noticeably when I perform a drag and drop within that container. If I move them back into my inventory, it seems to not do that anymore, the stutter is minimal. But if I try to put an item that can’t go into that container, it will start to produce this issue, for the items in that container.

I then tried to take a look in the DragItem.cs script, since I remembered that’s where we perform the item dragging and dropping.

I found the methods that took care of that, and basically what it does is the same thing, if you try to move the item into into a slot that either can’t take the item, or is not valid it does the AttemptSimpleTransfer method, where inside it removes and then adds the item. Now I don’t know if those 2 methods are the same as RemoveItem and AddToFirst slot from the inventory script, because those methods come from the IDragDestination and IDragSource scripts.

I thought that maybe I could somehow add a check into the DragItem.cs script, and have the item that is not able to go into that inventory container slot, act exactly like it does when you try to equip an equipment item into the wrong equipment slot.

I took a look inside the scripts but I couldn’t figure out where to do it or how to do it.

My question is, if there is a more simpler way and better way to do this? And a way that does not produce the performance issues that my way did.

Would appreciate if someone could help out.

Thanks

I haven’t done that part of the RPG course yet. For me to have a chance to help, you’d have to post the code.

In your profiler, did it say what was causing the micro stutter? Was it the garbage collector? Perhaps you’re creating and destroying items when dragging?

That all being said, it’s usually worth checking to see if it’s actually a problem that’s worth fixing. A micro stutter in the editor on a machine that (which I assume) isn’t as fast as it could be, might not be an issue once the game is built.

Context wise: A drop from 700fps to 680fps isn’t something that’d cause me to consider a fix, but if it forces it to go from 40fps to 10/20fps, I’d be ready to move heaven and earth to fix it.

I’m going to simplify this for you quite a bit, and it should take care of your issue…
You’ve already indicated that you’ve modified Inventory to specify the type of item it can accept:

In your InventorySlotUI.cs script, you’ll find a method

    public int MaxAcceptable(InventoryItem item)
    {
        if (inventory.HasSpaceFor(item))
        {
            return int.MaxValue;
        }
        return 0;
    }

This method is required in any IDragDestination, and is what tells the drag and drop system how many items you can put in the method.

This method links to Inventory.HasSpaceFor(item):

    public bool HasSpaceFor(InventoryItem item)
    {
        return FindSlot(item) >= 0;
    }

This is the method where you should put your check to make sure that the item is an item that your inventory will accept. If it’s not the right type, return false, if it is the correct type, return FindSlot(item)>=0;

This bypasses the AttemptedSwap completely, because if MaxAcceptable is 0, the drag system shouldn’t even attempt the swap at all.

1 Like

Thank you Brian! I don’t know why I didn’t thought of that, it actually does simplify my problem and makes it even easier for me to create multiple types of containers just by using an Enum.

I put the logic inside HasSpaceFor using a switch case, it works just fine, but there still seems to be an issue when I try to do any dragging and dropping inside that container.

I will post here a screenshot of the profiler, maybe someone can figure out exactly why. But like MichaelP said, it’s because of the Instantiate process. Because the course inventory system does rely on adding the item and removing it.

So I really don’t know if this issue can be fixed. I built the game, and it runs fine, but It does stutter just for a little second when I do that in the specific container.

Hmm, after testing a bit, one strange thing that I noticed was that, while moving items to the container which can take a specific type of item, if I have 2 of the same items that are not stackable, and I put them in different slots, everything is ok. If I try to put one of the same item over the other, I expected the same behavior as in the normal inventory, to “swap” their position. But no, instead, one of the same items just disappears. It does not happen with items that are not the same.

swap_item

That was in a built version of the project as I wanted to see how bad the stutter can get. I now checked it inside Unity, and this error comes up when I attempt to drop the same item onto them.

Maybe this is because of the way the containers are set? It doesn’t know what to do when the item is the same? Or it gets confused to which the source / drag container ir?

In terms of the profiler, I think a large part of this is that we’re not currently using Object Pooling with our Inventory Container at all. In fact, every time something changes in our Inventory, the entire InventoryUI Viewport is cleared, and a whole new set of InventorySlotUI are instantiated to replace the ones we just cleared. Depending on inventory size, memory, and processor speed, this can be a large temporary hit to the frame rate, and a large hit to the Garbage Collector.

We could alleviate this a couple of ways:

One is to assume that there will be a fixed inventory size. After the initial setup of the InventoryUI, you could save a reference to each InventorySlotUI and instruct them to refresh themselves. The downside of this is that it doesn’t leave a lot of room for growing or shrinking the size of the inventory at run time (perhaps as you level up, you unlock more inventory slots). The upside is that it’s relatively easy and cheap (clock cycle wise) to implement.

The next is to use Object Pooling, which would involve creating an InventorySlotUIFactory. Instead of destroying all of the InventorySlotUI in the InventoryUI’s viewport, each InventorySlotUI is returned to the InventorySlotUIFactory (Set the GameObject to inactive and change it’s parent to the InventorySlotUIFactory). When the InventoryUI needs a new InventorySlotUI, instead of instantiating one, it requests one from the Factory. The Factory checks to see if it has one as a child object, if it does, then it reactivates the object and returns it to the InventorySlotUI (which will Initialize it with the new object in it’s posession). If there are no InventorySlotUI available to the Factory, then it Instantiates a new one and returns it to the InventoryUI script.

The first thing I did when I saw this was zip into the course project to make sure that this isn’t a bug in our own system (Yes, I’ll admit it, we sometimes have bugs in our final code, and sometimes clever students find them). In this case, however, this is not happening. In fact, it’s also not happening in the window directly under the (very cool) UI with the equipment slots above it.

So it looks like it’s something that’s happening in the specialized inventory container…
Ideally, if you try to move a non-stackable item on top of an identical item, quite literally NOTHING should happen. The item being dragged should snap back into it’s original slot. That doesn’t appear to be happening in the modified container.

Let’s take a look at your completed HasSpaceFor method in your custom inventory. Paste it here and I’ll see if I can see what’s going on.

Sure, my idea was to use a switch on the inventoryType enum that i have created.

public bool HasSpaceFor(InventoryItem item)
        {
            switch (inventoryType)
            {
                case InventoryType.General:
                    if (item)
                        return FindSlot(item) >= 0;
                    break;
                case InventoryType.Spellbook:
                    if (item is Ability)
                        return FindSlot(item) >= 0;
                    break;
            }
            return false;
        }

For the “main” inventory, I thought to make a General type and assign it that, so that my inventory can accept any kind of items.

Ok, I don’t see an inherent problem with that at all. I’m curious, do you still have the extra code you mentioned in the beginning of the post (in AddToFirstEmptySlot and AddItemToSlot? If so, try resetting those methods to “factory” condition.

I actually removed those checks that I used to do in the AddToFirstEmptySlot and AddItemToSlot. They are basically the same as the course. So those methods are “factory” conditions.

Oh god… I feel so stupid… When that container opens up, it somehow is scrolled down a bit… So I cannot really see the first beginning slots… I just realized that on the attempt to swap… the item is actually added to the First empty slot that is available… I just scrolled up and I saw the items there. I’m really sorry.

LOL, That makes perfect sense. Don’t worry about it. This is how we work through bugs (or non bugs that are puzzling us)… going back and forth looking at all the possiblities. I actually didn’t notice that your scrollbar was part way down, as it’s just a tiny little sliver in the gif.

I haven’t found a way to constently force the scrollview to be at the top of the collection when the inventory is larger than the window size. That’s something that plagues me in my own games.

I really appreciate your help Brian, your solution really did simplify things A LOT and actually made what I wanted to achieve way more performant than it was before.

One thing that I am now curios about is the Object Pooling you mentioned for the UI. I noticed that in the game, whenever you attempt to do a drag and drop, in an empty slot, there is that tiny stutter that is not really noticeable but, if you try to swap between two slots that already have items in them, that’s when the stutter is noticeable. I mean, if you make your character move from point A to B, and then you do an item swap in between two different items, you will notice the stutter because of the frame drop.

Is this because on like, any action we do in our inventory, the InventoryUI script is basically redrawing the UI? or is it the way that the dragging and dropping works?

I would like to read more on object pooling and try to figure out how to make that work with the course inventory system.

Go have a quick read on the wiki page for Object pooling. That’s the basics. After you’ve read, ask questions. I’ve programmed a few object pooling systems. Once you have the basics downpat and done it a few times, they’re not as mysterious as everyone originally thinks they are.

https://en.wikipedia.org/wiki/Object_pool_pattern

Thanks for the help everyone, I’ll take a look into Object Pooling and see what I can do.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms