Using and Creating Resources in Godot 4

Any game out there needs assets like textures, sounds, and music to provide a fun experience to its players. Godot treats these files as resources you can use throughout your project. Besides Godot’s built-in resources, you can also create your own to build powerful, modular systems. Custom resources make it easier to manage your project. […] By Eric Van de Kerckhove.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Creating a Shop Display

Printing some text to the output window is great and all, but displaying the items with their sprites and other properties is more fun!
To get that done, you’ll need to add some logic to the shop item display so it can fill in its labels based on an item. Once that’s done, the shop script can instantiate the shop item displays based on its inventory.

To add some logic, you’ll need a new script, so open the shop_item_display scene and select the ShopItemDisplay node at its root. Add a new script to it named shop_item_display.gd and make sure to place it in the scripts folder.
Here’s what this script should do:

  • Get references to the sprite, labels and the button
  • Store a reference to an item
  • Update the UI elements based on the item’s properties
  • Emit a signal when the buy button was pressed

To start off, add the following code below the extends line:

class_name ShopItemDisplay # 1

signal buy_pressed(item_display : ShopItemDisplay, item : Item) # 2

Here’s a summary of this code:

  1. As always, a class name helps with static typing as you’ll see in the next line.
  2. This signal will be emitted when the buy button is pressed. It has two parameters: the item display that emits the signal and the item that’s being sold by the display. This signal will be used by the shop script later on.

Next up are the references to the Control nodes. To add these, select all children of the BackgroundTexture node and drag them to the code editor while holding Control/Cmd. This will create all necessary @onready variables.

Drag controls to script

Here’s the code it added:

@onready var sprite_texture: TextureRect = %SpriteTexture
@onready var name_label: Label = %NameLabel
@onready var hp_label: Label = %HpLabel
@onready var attack_label: Label = %AttackLabel
@onready var defense_label: Label = %DefenseLabel
@onready var buy_button: Button = %BuyButton

Now add these lines of code below the @onready variables:

var linked_item : Item # 1

func link_to_item(item : Item): # 2
    linked_item = item # 3
    _update_info() # 4

You’ll get an error because the _update_info function isn’t defined yet, but ignore that for now.

Update info not found error

The link_to_item function will be called by the shop script while adding new shop displays. It will store a reference to an item in the linked_item variable and call the _update_info function to update the display.
Here’s what this code does line-by-line:

  1. The linked_item variable stores a reference to an item
  2. A function called link_to_item that takes an item as a parameter
  3. Store the item reference in the linked_item variable
  4. Call the _update_info function to update the display

Now add the following code below the link_to_item function:

func _update_info():
    # 1
    name_label.text = linked_item.item_name
    sprite_texture.texture = linked_item.sprite
    hp_label.text = str(linked_item.hp)
    attack_label.text = str(linked_item.attack)
    defense_label.text = str(linked_item.defense)

    buy_button.text = "Buy\n" + str(linked_item.price) + "G" # 2
    buy_button.pressed.connect(_on_buy_pressed) # 3


func _on_buy_pressed():
    buy_pressed.emit(self, linked_item) # 4

The _update_info function will update the display based on the item’s properties. It will also link the buy button’s pressed signal to the _on_buy_pressed function. The _on_buy_pressed function in turn will emit the buy_pressed signal.
Here’s what’s going on in more detail:

  1. Update the all labels based on the properties of the item. The str function is used on integers to convert them to strings.
  2. The text of the buy button is updated to include the price of the item
  3. Connect the buy button’s pressed signal to the _on_buy_pressed function
  4. Emit the buy_pressed signal and pass the shop item display and the item

That finishes up this script! Save it and open the shop.gd script again.

Showing the Shop Items

The shop script should create a shop item display for each item in its inventory.

Shop displays

For that to work, it needs a reference to a Control node where it can put the displays and a reference to the shop display scene.

First, add these two variables below the shop_inventory variable declaration:

@onready var shop_item_display_h_box: HBoxContainer = %ShopItemDisplayHBox # 1
@export var shop_item_display_scene : PackedScene # 2

Here’s what they’re for:

  1. shop_item_display_h_box is a reference to the HBoxContainer node, this is where you will put the shop item displays
  2. The shop_item_display_scene export variable will reference the shop_item_display scene

Next, add this function below the _ready function:

func update_shop_items_display():
    for child in shop_item_display_h_box.get_children(): # 1
        child.queue_free()

    for item in shop_inventory.items: # 2
        var new_item_display = shop_item_display_scene.instantiate() as ShopItemDisplay # 3
        shop_item_display_h_box.add_child(new_item_display) # 4
        new_item_display.link_to_item(item) # 5
        new_item_display.buy_pressed.connect(_on_item_display_buy_pressed) # 6

This function will first remove all existing shop item displays. It will then instantiate a shop item display for each item in the shop’s inventory. Finally, it connect the buy_pressed signal to the _on_item_display_buy_pressed function, which you’ll add next.
Here’s how it works:

  1. Loop through the existing children (the item displays) of the HBoxContainer and remove them
  2. Loop through the items in the shop’s inventory
  3. Instantiate a new shop item display
  4. Add the display to the HBoxContainer
  5. Pass the item to the shop item display to link it
  6. Connect the shop item display’s buy_pressed signal to the _on_item_display_buy_pressed function

Now for _on_item_display_buy_pressed, add this below the update_shop_items_display function:

func _on_item_display_buy_pressed(item_display : ShopItemDisplay, item : Item): # 1
    print("Sold " + item.item_name) # 2
    item_display.queue_free() # 3

This will print the sold item name to the output window and remove its item display:

  1. This function is called when the buy button is pressed, it has the same parameters as the buy_pressed signal
  2. Print the sold item name
  3. Remove the item display

To finish up the script for now, the update_shop_items_display function should be called when the shop loads. Remove all code from _ready function and add this line in its place:

update_shop_items_display()

To get the displays to work, save the script and drag the shop_item_display scene from the scenes/shop_ui folder in the FileSystem dock onto the Shop Item Display Scene property of the Shop node.

Drag shop item display

Now run the project and try buying some items! The displays should reflect the items in the inventory. Whenever you click a buy button, the display should disappear and the item’s name should be printed to the output window.

Buying items

As a cherry on top, open the shop script again and add a reference to the CashSound node right above the _ready function:

@onready var cash_sound = $CashSound

You’ll use this to play a nice cash register sound when you buy an item. Add this line at the end of the _on_item_display_buy_pressed function to do so:

cash_sound.play()

Save the script and run the project once more. You should hear a satisfying sound play now whenever you buy an item.

Ka-ching sound plays

Almost feels like a shop you’d find in a monster-collecting game, right? :]
To take your custom resource skills to the next level, you’re going to add some logic to the Inventory resource.

Contributors

Over 300 content creators. Join our team.