Let’s continue our Hack’n’slash and start working on our inventory system!
This article is also available on Medium.
Ok – so far in this tutorial, we’ve already implemented various important features for our game: the movement, the attack combos, cross-platform inputs… Today, we’re going to start another big one: the inventory system.
A quick overview of our soon-to-be inventory system
This time, we’re drawing more on the Diablo series than a roguelite like Hades – the inventory is a component that you usually find in RPG games because it assumes your hero progresses as you play (which is kind of antithetic with the roguelite/roguelike genre).
However, I’m also going to mix the Diablo inventory system with the ones from The Elder Scrolls: Skyrim and from World of Warcraft. Let me explain 🙂
If you’ve ever played Diablo III (or a game from the Neverwinter Nights series, for that matter), you might remember that these games require you to optimise how you store the objects in the inventory to not lose unnecessary storage cells:
This mechanic is cool but I feel like it’s a bit too much for our game. Instead, I’d rather have:
- a limited total number of slots with some item stacking (like in World of Warcraft):
- and a total maximal weight that the hero can carry (like in Skyrim):
Ultimately, the player will be able to loot items, stack them and drop them out of the inventory if need be. We’ll also have a separate slot for the coins, or gems, or whatever currency you want for your game.
So, in the end, we should have something like this:
As you can see:
- the different items are stored in different slots
- when possible, items of the same type are stacked together (for example the apples)
- for each filled slot, we show the icon of the item inside it as well as the amount if there are more than one
- I have the current and total weight in the bottom-left corner
- I have my “money” in the bottom-right corner
We will also have several item types: Weapon, Armour, Component and Misc(ellaneous).
And finally, just like in Diablo or World of Warcraft, a handful of item rarities (associated with colours): Common (Blank), Uncommon (Green), Rare (Blue), Epic (Purple) and Legendary (Orange).
Now that we have an idea of what we want to create, time to get to it! And today, to begin with, we’ll prepare the UI panel by taking some free assets from the Unity Asset Store and populating a UI canvas.
Alright – let’s go 🙂
Getting some quick-win assets
For several years, my prototypes have oftentimes been filled with cubes, and spheres, and blank squares. Being (primarily) a programmer, I usually delay the moment where I make “okay” assets and start to fill my project with placeholders or primitives – because what I like the most is writing code and designing logic systems.
The problem with that technique is that what you put in your project as placeholder… often becomes permanent! That’s why real good game dev teams have concept artists, and 3D modellers, and animators, and VFX specialists that work hand in hand with the devs to continuously feed the project with professional quality assets.
This can be especially important for specific systems, like an inventory. If you think about it, from a developer point of view, inventories are about putting items in slots. But if you don’t have a quick way of distinguishing between your items, it’s going to take a longer time to set up everything. Suppose you put labels instead of icons in the slots, because you don’t have any images ready: you’ll have to read through each and it will slow down your tests significantly.
Of course, it’s not always possible to have good assets readily available. If you’re working on an actual game project that you eventually want to sell, you’ll need to do your own artwork – and if you do it alone, you’ll obviously need to divide your time between programming and creating resources, so you might not have everything ready when you want it.
But here, I’m making a prototype and the point is to have something that works and that teaches us something. So I don’t really care about having unique assets. Also, the nice thing is that I’ve set my game in a very classic “medieval fantasy RPG world”… which means that I can easily find fitting assets made by other people for this kind of universe! 🙂
So I went to the Unity Asset Store and I got two completely free packages to quickly populate my game with some UI elements:
- the Free UI Pack by Valley Land Games: this is a bundle of various backgrounds, frames, borders and icons (grouped in a Sprite Atlas) to quickly design a simple game UI with panels, buttons, menus, sliders…
- the RPG inventory icons by REXARD: this set of 25 hand-drawn icons is really cool to populate the game with very common RPG items like swords, axes, potions, helmets…
Note that the author also offers a paid “megapack” of icons with a ton more fantasy-styled hand-drawn images!
To add those libs to your project, all you have to do is add the assets to your Unity account and import them into the Unity project.
Setting up the UI Canvas and events
Unity, like all major game engines, has various great tools to create user interfaces (UI) quickly and easily. In fact, there are now three UI systems available in the framework: the UI Toolkit, the Unity (Canvas-based) UI, the IMGUI.
The UI Toolkit is interesting because it uses “classical” interface tools like CSS and XML, but it is not built-in. On the other hand, the Canvas-based UI is another good choice for designing slick and responsive UIs, and it is available by default!
If you take a look at the Free UI Pack, you’ll see that there are several prefabs you can use directly, like frames or buttons, and that this lib is meant to be used with the Canvas-based UI.
So the first step is to create a Canvas in our scene:
To get a responsive UI that scales with the size of the screen, you can change the scale mode of the Canvas Scaler component and choose your reference resolution:
This screen size-dependent scaling is my preferred mode for the Canvas Scaler… but there are several ways of setting up a UI, and you might prefer to handle responsiveness differently (in particular if you plan on making a mobile game) – be sure to peek at the Unity docs for more info on the various scale modes 🙂
Anyway – when you create a Canvas object, you’ll also see that Unity also adds an “EventSystem” game object alongside it. This object is here to catch and react to the user’s inputs (like clicking on a button for example).
However, if you select this object, you’ll notice that for now the event system shows an error because it is not properly configured for the new input system:
To fix this, click on the button – the component will automatically be replaced by another one that is compatible with the new system:
But! You need to be careful about the input actions asset that is used. For now, Unity assigned a default one that is not the asset we started to configure in our previous tutorials.
What we want to do is:
- copy those UI-related actions back into our own input actions asset
- set this asset in the UI Event System component
To copy the actions, all you have to do is open the editors for each input actions asset (ours and the default one), right-click on the actions map and click “Copy”; then in the editor of our input actions asset, right-click in the left column and click “Paste”:
Of course, when you’re done, don’t forget to re-assign our input actions asset into the Input System UI Input Module component 😉
Creating the inventory panel
Now that our Canvas is ready, we can finally add our inventory panel!
My goal here is not to suggest any “best” layout – of course, you should feel free to adapt it to your own game. I’ll simply describe how I setup my own UI 🙂
Overview of the panel hierarchy
The panel is divided in three parts: the title box at the top, the items grid in the middle and the info bar at the bottom.
Something to remember, though, is that the objects that are highest in the hierarchy are drawn first, or in other words behind the rest. So, here, to make sure the borders overlap properly, we’ll put the items grid at the top of the children list, then the grid border, then the title box and finally the info bar:
The frames and backgrounds are simply prefabs from the Free UI Pack where I’ve changed the colour and added some UI elements. The UI texts re-use the TextMeshPro package we installed previously – to create TMPro UI text objects, just use the GameObject menu and make sure to set the new object as a child of the Canvas (it can be nested anywhere underneath it).
Also, the weight and money displays use a Horizontal Layout component to place the icon and the text next to each other.
Scaling the title box
As you can see, the title box stretches across the entire width of the panel. This can be done easily by setting the Rect Transform of the UI element to “stretch” mode:
Now – my title box is based on one prefab from the Free UI Pack: “Bar_1”. However, if I just add this prefab to the panel and stretch it horizontally, I get a really thick border:
The problem is that, for now, I don’t have any control over the size of the border! When I scale the element, all the images are scaled directly.
To solve this issue, we need to use the Unity 9-slicing sprite technique.
In short, 9-slicing sprites are a way of re-using the same asset at various sizes while limiting the weird stretching. The idea is to cut down the initial sprite into nine portions and then copy each portion with constrained scaling. If we take a look at Unity’s docs, we have a basic example to better understand this slicing:
Here, the image is divided into:
- 4 corners A, C, G and I: those get cut and pasted but not stretched
- 4 borders B, D, F and H: the B and H borders can be stretched horizontally but not vertically, and the D and F borders can be stretched vertically but not horizontally
- 1 center zone E: it can be stretched horizontally or vertically
So: to make a 9-slicing sprite, we first have to change the “Image Type” of the Image component. This property determines how your image is displayed and how it is stretched in the UI when you change the size of the UI element itself. It can take four values: “Simple”, “Sliced”, “Tiled” or “Filled”.
Note: for more info on those various image types, you can check out this other article I wrote recently.
But if you try to change to this image type, you’ll see that you have a little warning telling you: “This image doesn’t have a border”.
That’s because, for now, we haven’t cut down our sprite into the nine required portions! To do this, we have to edit the Sprite Atlas to define borders on the sub-sprites inside the Free UI Pack asset.
More precisely, we want to click the “Sprite Editor” button…
In the most recent versions of Unity, it isn’t built-in anymore and so you’ll first need to install it thanks to the Package Manager:
Once the plugin is added to your project, you’ll be able to click the button to open the Sprite Editor panel. In this editor, you can select each sub-sprite to set its properties – and, in particular, the size of its top/right/bottom/left borders. Here, the frame image has 16px-thick borders. Once you’ve set the borders, remember to “Apply” the modifications with the button at the top 🙂
Now that the asset is configured, we can use the “Sliced” type and play with the “Pixels Per Unit Multiplier” value to control the thickness of the border:
This way, I can get a more adapted ratio and a nicer visual for my title box (here’s a before/after comparison):
Preparing the items grid
Finally, let’s wrap up this episode by discussing how to setup the grid of items in the middle of the panel.
The core idea is to use the Grid Layout component to automatically place the square inventory slots – after tweaking the values around a bit, I eventually got to a 7 by 8 grid, i.e. a total of 56 inventory slots, where each slot is a square of 105×105 pixels. The grid itself also stretches to fill the panel as much as possible with some top/right/bottom/left offsets.
The inventory slots themselves are a simple re-adaptation of the “Icon_1” prefab from the Free UI Pack, but with some extra components:
- the “Icon” is a UI element with an Image component – it stretches across the entire element with a little bit of padding
- the “Rarity” is another Image: I’ve set it to the “f” sprite of the Free UI Pack and it will be a way of highlighting items with a non-Common rarity
- the “Amount” is a TextMeshPro UI text stuck in the top-right corner
Note also that I’ve toggled the “Raycast Target” option off on all the Image components of these elements except for the “Background”:
And that the three “Icon”, “Rarity” and “Amount” children are disabled because, by default, the slot needs to be empty.
Finally, I’ve simply instantiated this prefab 56 times as children of my “Items” UI element (the one with the Grid Layout) and to position them automatically and get my basic (empty) inventory panel:
Just a quick final note…
Of course, by default, we want the inventory to be hidden. We’ll see next week how to toggle it with some keyboard key, just for tests, and later we’ll work on cross-platform inputs for the inventory.
But in the meantime, you can just set the game object inactive in the scene 🙂
In this episode, I’ve described the main features of the inventory system we’ll implement in the upcoming weeks, I’ve listed some nice free resources that can be used to get more accurate and readable placeholders and I’ve discussed how I’ve setup my UI inventory panel.
If you want to see it in more details, be sure to take a look at the Github repo of the project 🚀
Next time, we’ll continue working on this inventory system and see how to define item data, add items to the inventory, handle stacking…