How to Build an Inventory System in Godot 4 (original) (raw)
Unlock the secrets to efficiently managing your game assets with our comprehensive guide to creating a dynamic inventory system in Godot!
Crafting a robust inventory UI is critical to many games – allowing players to carry, use, and manage a variety of items. In this guide, you’ll learn to set up an inventory system complete with slots to store and display items, buttons for interaction, as well as scripts to piece all these together for a complete, functioning inventory system in Godot. We will also be focusing on creating the UI side of this inventory with labels and icons for items in inventory slots – so your inventory system will be ready from both the frontend and the backend.
This tutorial is great for those with a basic understanding of Godot and GDScript. In addition, you can also explore our full course, Craft an Inventory System with Godot 4 which covers these concepts more in-depth – including integrating your inventory with in-game items more robustly.
Let’s dive in!
Table of contents
- Inventory System Project Files
- Inventory UI
- Creating the Scripts
- Inventory Script
- Inventory Slot Script
- Inventory System Wrap-Up
Inventory System Project Files
This tutorial contains extensive code samples and references. For those interested in using the same assets we did in our inventory system for comparison, we have included the complete assets collection used.
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
AVAILABLE FOR A LIMITED TIME ONLY
In this first section, we will be setting up an inventory UI in Godot. The inventory UI will be the window that appears when we open our inventory. It will have a number of different slots that we can interact with, as well as the ability to hover over an item and see what it’s called. Let’s start.
Creating the Inventory Nodes
First, we need to decide where this inventory is going to be stored. In this case, we have our player node, and we want our inventory to follow our player around if we have it in other scenes. So, we will create our inventory nodes in the player scene.
Open up the player scene and create a new blank node and call it “inventory”. This is where our inventory script will be managing all of our items.
Add a child node to the inventory node. This node should be of type “panel”. This will be the UI panel that we will enable and disable.
Set the size of the panel to your desired dimensions and center it in the window.
Rename this panel to “inventory window”.
Creating the Inventory Slots
Next, we need to create our inventory slots. For this, we will use a grid container node which will automatically arrange all of its children nodes into a grid formation. We also need a button node for each slot, because we are going to be able to click on it.
Right-click on the inventory window and add a child node. This node should be of type “grid container”.
Increase its size to be slightly smaller than our panel as a whole and set the anchoring to be center.
Create a child node of the grid container of type “button”. This will be our inventory slot.
For the button, set the custom minimum size so that it fits properly in the grid container. We used 96 x 96 for ours, but any size will work.
You can now test your inventory by duplicating the button within the GridContainer. By clicking the Grid Container, you can choose how many columns the grid should have and it will move items to the next row automatically.
Adjust the sizing until you find something that looks good.
Afterward, delete all but one button as we need to do some more work on our base object. Before we move on, rename the GridContainer to “SlotContainer” and the Button to “InventorySlot”.
Setting up the Inventory Slot
Each inventory slot will need an icon texture to display what the item looks like, and a label to display how many of that item we have. Create a child node of the inventory slot of type “TextureRect”. This will represent the item’s texture.
Rename the node to “Icon” in the hierarchy so that we know it’s for our texture image.
For these next steps, feel free to drop in a texture for the Node’s texture value if you want for testing purposes (we’ll have done so for our demonstration). Regardless, the next step is to set the expand mode to “Ignore” so we have control over the node’s size.
Set its size and anchoring to center.
Create another child node of the inventory slot of type “Label”. This will represent the item’s quantity, so we will rename it to “QuantityText”.
Set the anchoring to the bottom right.
Then, adjust the label’s settings to your liking. There is no right or wrong here. For ours, we set the horizontal alignment to Right and the vertical alignment to Bottom.
After, we created new Label Settings, changed the size to 32 px, and added a black shadow of 1px to the label.
This gave us a final look as seen below:
Creating the Inventory Scripts
Now, we need to create scripts to manage our inventory. We will need two scripts: one for the inventory and one for each inventory slot. Create a new script called “inventory” and attach it to the inventory node.
Repeat this, creating another script called “inventory slot” and attaching it to the inventory slot node.
Finishing the Inventory Slot
Before we jump into writing our scripts, we need to do a few finishing touches.
First, in both our Icon and QuantityText nodes, we want to set the filter to Ignore in the Inspector for the mouse. In this way, when we click on the InventorySlot, we won’t be blocked from clicking the button parent. This could lead to glitchy functionality otherwise.
With this done, drag the InventorySlot into the FileSystem to make it into a Scene.
You can now test out your inventory by duplicating the scene. If needed, you can select the SlotContainer and adjust the H Separation and V Separation values until you get a grid you like.
Play around with things until you get something you’re happy with.
Info Text
The last UI element we want to add is some info text so we can display information about selected items. To do this, create a child node of the InventoryWindow of type Label. We will rename the label “InfoText”.
Anchor the InfoText to the bottom right and select it to fully stretch across the screen.
Horizontally align the text so it’s centered (and feel free to enter placeholder text to test out your font).
Create some new label settings and change the text as desired. All we did was change the size to 18.
If necessary, adjust the position of the grid and info text so that they fit nicely within the panel.
That’s it for setting up our inventory UI. In the next part, we will start coding the functionality of our inventory system.
Creating the Scripts
In this next part, we will set up our scripts for our inventory system in Godot. The inventory system will have slots, each of which will contain an item and display its quantity. Let’s start by setting up the script for our inventory slot.
Setting up the Inventory Slot Script
The inventory slot script will manage each slot inside our inventory. Each slot will need to know the type of item it contains and how much of it is there. It will also need references to its icon and quantity text child node and to the inventory itself.
Here’s how we can set up the basic structure of our inventory slot script:
class_name InventorySlot extends Node var item : Item var quantity : int @onready var icon : TextureRect = get_node("Icon") @onready var quantity_text : Label = get_node("QuantityText") var inventory : Inventory
We will also need some functions for our inventory slot. These functions will allow us to set the item, add an item, remove an item, and update the quantity text. We will also have interaction-focused functions, such as pressing the button, right-clicking on it, and hovering over it. Here’s how we can define these functions:
func set_item (new_item : Item): pass func add_item (): pass func remove_item (): pass func update_quantity_text (): pass
Setting up the Inventory Script
Now let’s move on to setting up our inventory script. This script will manage all of our inventory slots. We will need an array to store our slots, a panel for our inventory window, a label for our info text, and an array for our starter items.
Here’s how we can set up the basic structure of our inventory script:
class_name Inventory extends Node var slots : Array[InventorySlot] @onready var window : Panel = get_node("InventoryWindow") @onready var info_text : Label = get_node("InventoryWindow/InfoText") @export var starter_items : Array[Item]
We will also need some functions for our inventory. These functions will allow us to toggle the inventory window, add an item, remove an item, retrieve a slot to add/remove an item, and get the total quantity of a specific item. Here’s how we can define these functions:
func _ready (): pass func _process (delta): pass func toggle_window (open : bool): pass func on_give_player_item (item : Item, amount : int): pass func add_item (item : Item): pass func remove_item (item : Item): pass func get_slot_to_add (item : Item) -> InventorySlot: return null func get_slot_to_remove (item : Item) -> InventorySlot: return null func get_number_of_item (item : Item) -> int: return 0
And that’s it! We have set up the basic structure of our inventory system. In the next section, we will start filling in these functions to make our inventory system functional.
Inventory Script
With our base inventory system skeleton set up, we will continue building our inventory system in Godot. We’ll start by setting up our inventory window to be hidden at the start of the game. Next, we’ll assign slots for our inventory items and add functionality to populate these slots with our starter items. Finally, we’ll build the functionality to open and close the inventory window and display the mouse when the inventory is open.
Setting Up the Inventory Window
To begin with, we will set our inventory window to be closed at the start of the game. We will use the `toggle_window` function and set it to `false`. This will ensure that our inventory window is closed when the game begins. The code for this is as follows:
func _ready (): toggle_window(false)
Assigning Slots for Inventory Items
Next, we need to assign slots for our inventory items. Right now, our slots are just an empty array and we need to populate them. To do this, we will loop through all the children nodes of the slot container and assign them to the slots array. The code for this is as follows:
for child in get_node("InventoryWindow/SlotContainer").get_children(): slots.append(child) child.set_item(null) child.inventory = self
Here, we are looping through each child node inside the slot container and adding them to the slots array. We are also setting their item to be null. This is because we don’t want any default icons or text, we want the slots to be blank at the start of the game.
Adding Starter Items to the Inventory
Now that we have our slots set up, we can add our starter items to the inventory. To do this, we will loop through our `starter_items` array and add each of those items to the inventory. The code for this is as follows:
for item in starter_items: add_item(item)
Opening and Closing the Inventory Window
The next thing we need to do is add functionality to open and close the inventory window. We will use the `toggle_window` function again, but this time we will pass in a boolean value that is the opposite of the current visibility of the window. This will toggle the visibility of the window. The code for this is as follows:
if Input.is_action_just_pressed("inventory"): toggle_window(!window.visible)
Here, we are checking if the inventory action has been pressed, and if so, we are toggling the visibility of the window. Note that if you haven’t done so already, you will need to set up the “inventory” action within the Input Mapping of your Godot project. We used the tab key for ours, but you can use “I” or any key you want.
Displaying the Mouse When the Inventory is Open
When the inventory window is open, we want the mouse to be visible. To do this, we will set the mouse mode to visible when the window is open and captured when the window is closed. The code for this is as follows:
func toggle_window (open : bool): window.visible = open
if open: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE else: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
Adding the Item
Now that we can access the inventory, let’s create a function to be able to add an item to the inventory. We first need to find the slot that we’re going to add it to, and send the item to that slot.
func add_item (item : Item): var slot = get_slot_to_add(item)
However, if there is no slot returned (i.e. our inventory is full), we’ll need to return out of this function.
func add_item (item : Item): var slot = get_slot_to_add(item)
if slot == null: return
Finally, we need an if-else statement to check whether or not the item is already in the slot we got back. If the slot is empty, we’ll set the slot as that item. However, if the item is already in the slot, we’ll just increase the quantity.
func add_item (item : Item): var slot = get_slot_to_add(item)
if slot == null: return
if slot.item == null: slot.set_item(item) elif slot.item == item: slot.add_item()
Removing an Item
We can add the item, but we’ll also want to be able to remove it. This will be slightly reminiscent of how we approached the solution above. First, we find the slot we want to remove. If we don’t get a slot back or the slot doesn’t have the item we’re trying to remove, we need to return out of the function. Otherwise, we’ll remove the item!
func remove_item (item : Item): var slot = get_slot_to_remove(item)
if slot == null or slot.item == item: return
slot.remove_item()
Getting the Slot
You might have noticed above we’re using some functions we have yet to implement in order to get the slot. In this section, we’ll be implementing some search functionality so we can find our slots.
Let’s first set up our function that searches through our slots so we can add an item. Our function will do a few things:
- First, we’ll make sure we’re receiving the item we want to look for as a parameter so we know what item to look for
- We’ll loop through all our slots, checking each one to see if the slot has our item and if it’s less than the item’s max stack size. If we find a matching case, we’ll return that slot.
- For instances where we never find a slot with a matching item or applicable quantity size, we’ll loop through our slots again to see if there is an empty slot. If there is, we’ll return that slot.
- If we can’t add our item or there are no empty slots, we’ll return null. This will allow our add item function above to exit it out of itself.
func get_slot_to_add (item : Item) -> InventorySlot: for slot in slots: if slot.item == item and slot.quantity < item.max_stack_size: return slot
for slot in slots: if slot.item == null: return slot
return null
Now we can search our list successfully to add an item. Searching the list for an item to remove is even simpler, though similar to the code above. In this case, we loop through our slots looking for a slot that contains our item. If it finds it, it returns that slot. Otherwise, it returns null so we can tell our remove item function that there’s no item to remove.
func get_slot_to_remove (item : Item) -> InventorySlot: for slot in slots: if slot.item == item: return slot
return null
Return Item Quantity
The last thing we need is the ability to return the item’s quantity. To do this, we’ll first need a variable to track the total of that item. Then, similar to searching, we’re going to loop through each slot looking for our item. If it finds that item, it’s going to increase the total of the slot’s quantity value. At the end, we just return the final total.
func get_number_of_item (item : Item) -> int: var total = 0
for slot in slots: if slot.item == item: total += slot.quantity
return total
And that’s it for this lesson! We’ve set up our inventory window to be hidden at the start of the game, assigned slots for our inventory items, added functionality to populate these slots with our starter items, and built the functionality to open and close the inventory window and display the mouse when the inventory is open. We also added the functionality to add and remove items.
In the final part, we’ll work on connecting the inventory slots to the inventory system.
Inventory Slot Script
Next, we’ll be focusing on the inventory system of our game, specifically on the inventory slot script that we set up in previous lessons. We’ll be working on implementing the functions for setting, adding, and removing items from the inventory slots, as well as updating the quantity text and adding interaction functionality.
Setting Items
The ‘set item’ function will be called when we want to assign an item to a slot. We’ll first create an item variable and assign a new item to it. By default, we’ll set the quantity of the item to one. If the item we’re assigning is null, meaning we want to empty the slot, we’ll set the icon visibility to false. If the item does exist, we’ll set the icon visibility to true and set the icon texture to the icon we assigned earlier. We’ll also call the ‘update quantity text’ function.
func set_item (new_item : Item): item = new_item quantity = 1
if item == null: icon.visible = false else: icon.visible = true icon.texture = item.icon
update_quantity_text()
Updating Quantity Text
In games with an inventory system, the quantity of an item is often displayed as text. For example, in Minecraft, if you have one of an item, it displays nothing. But if you have more than one, it displays the quantity. We’ll implement similar functionality here. If the quantity of an item is less than or equal to one, we’ll display an empty string. Otherwise, we’ll display the quantity. We’ll also convert the quantity number to a string.
func update_quantity_text (): if quantity <= 1: quantity_text.text = "" else: quantity_text.text = str(quantity)
Adding and Removing Items
The ‘add item’ function will be called when we want to increase the quantity of an item in a slot. We’ll increment the quantity by one and then update the quantity text. The ‘remove item’ function will be called when we want to decrease the quantity of an item in a slot. We’ll decrement the quantity by one, update the quantity text, and if the quantity is zero, we’ll set the item to null, meaning it no longer exists in our inventory.
func add_item (): quantity += 1 update_quantity_text() func remove_item (): quantity -= 1 update_quantity_text()
if quantity == 0: set_item(null)
Interacting with Items
We’ll also add functionality for detecting when we click on items in the inventory. This will involve a left click and a right click. We’ll first add a ‘pressed’ signal that gets called when we left-click on a button. When the button is pressed, if the item is not null, we’ll call the ‘on use’ function of the item. We’ll also send over the player to the ‘on use’ function because it has a player parameter. If the ‘on use’ function returns true, meaning the item should be removed after use, we’ll call the ‘remove item’ function.
func _on_pressed(): if item == null: return
var remove_after_use = item._on_use(inventory.get_parent())
if remove_after_use: remove_item()With these functions implemented, we now have a functional inventory system that allows us to add, remove, and interact with items. In the next lesson, we'll look at setting up world items so that we can pick them up and drop them in the game world.
And now we should have a functioning inventory:
Inventory System Wrap-Up
Congratulations on making it to the end of this thorough tutorial! You now have a fully functioning inventory system in Godot – rounded off with the ability to display, pick up, manage, and drop items, all through the inventory system you’ve written with GDScript.
From this point, you are well-equipped to expand the inventory system to offer greater depth, include more features, or adapt it into your future Godot projects. You could consider creating unique interaction actions for specific items or incorporating sound for inventory interactions. For example, in the free video tutorial below, you’ll see how similar concepts can be combined to start making a crafting system for your game.
Why stop here? Continue to expand your game development knowledge with Zenva’s exciting range of comprehensive tutorials and courses – from delving into RPG mechanics, achieving realism through physics simulations, or even tapping into Virtual Reality.
Embed your newfound knowledge in your upcoming projects and continue gaining expertise in the Godot Engine. Happy game crafting!
Curious to dive deeper? Enroll in our comprehensive CRAFT AN INVENTORY SYSTEM WITH GODOT 4 course today!
Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!