How to Build an Inventory System in Godot 4

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!

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.

Download Project Files Here

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Inventory UI

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.

Godot Scene Hierarchy showing the new Inventory child node

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.

Godot Scene Hierarchy showing the Panel child of the Inventory node

Set the size of the panel to your desired dimensions and center it in the window.

Panel in Godot being resized and centered with the Anchor tool

Rename this panel to “inventory window”.

InventoryWindow node in Godot with panel to the right in the editor

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”.

Create New Node window from Godot with the Grid Container node selected

Increase its size to be slightly smaller than our panel as a whole and set the anchoring to be center.

GridContainer in Godot editor resized and centered with the Anchor tool

Create a child node of the grid container of type “button”. This will be our inventory slot.

Godot Scene Hierarchy showing parenting child relationship of the Inventory so far with the button added

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.

Button Node in the Godot Inspector with the Custom Minimum Size property circled

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.

Godot Inspector for the GridContainer showing the Columns property

Adjust the sizing until you find something that looks good.

Test inventory in the Godot grid using buttons

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”.

Godot Scene Hierarchy showing the renamed nodes relevant to the inventory

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.

Create New Node window in Godot with the TextureRect node selected

Rename the node to “Icon” in the hierarchy so that we know it’s for our texture image.

Godot Scene Hierarchy with the Icon node highlighted from renaming it

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.

Godot Inspector for the Icon with the Expand Mode property circled

Set its size and anchoring to center.

Icon in Godot being resized and centered

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”.

Godot Scene Hierarchy with QuantityText label node added

Set the anchoring to the bottom right.

Label for the Inventory in Godot being anchored 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.

Label in the Inspector with the alignment settings shown

After, we created new Label Settings, changed the size to 32 px, and added a black shadow of 1px to the label.

Label Settings in Godot for the QuantityText label

This gave us a final look as seen below:

Example Inventory Slot finished for the Godot Inventory project

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.

image 111

Repeat this, creating another script called “inventory slot” and attaching it to the inventory slot node.

InventorySlot script added to the InventorySlot 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.

Mouse settings in the Godot Inspector with Ignore set for the filter.

With this done, drag the InventorySlot into the FileSystem to make it into a Scene.

Godot FileSystem showing the InventorySlot 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.

H Separation properties and V Separation properties from the Godot Inspector

Play around with things until you get something you’re happy with.

Inventory with all slots demo in Godot

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”.

Godot Scene Hiearchy with the InfoText label node added

Anchor the InfoText to the bottom right and select it to fully stretch across the screen.

Godot anchor presets with the bottom full stretch option selected.

Horizontally align the text so it’s centered (and feel free to enter placeholder text to test out your font).

InfoText label with the Horizontal Alignment property shown in the Godot Inspector

Create some new label settings and change the text as desired. All we did was change the size to 18.

InfoText node label settings in Godot with the Size property highlighted.

If necessary, adjust the position of the grid and info text so that they fit nicely within the panel.

Inventory demonstration in Godot with the info text and grid both added

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.

Godot Project Settings showing the key mappings for a Godot project

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:

  1. 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
  2. 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.
  3. 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.
  4. 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.

Demo of the main inventory functionality in Godot

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:

Fully rendered inventory system in Godot

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.

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!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.