Getting input from buttons created in a for loop

Godot Version

4

Question

I have been working on a textRPG and now I’m trying to implement an inventory system. It’s working fairly well, except for allowing a player to pickup a new item in a room.

I am using a for loop to create a label and button for each item in an array, then assigning the button and label text for each.

I am unsure how I could actually get the input from that button, since any way I try to name it doesn’t work - I can’t give it a set name because its in a for loop (I tried things like .name(“Button” + i) but that didn’t work.)

1 Like

I have managed this sort of thing by creating a new class extended from Button.

I tend to put my signal definitions in a global file to start with and then move them to a more proper scope when I get my head around exactly where I need them.

SomeGlobalFile.gd

extends Node
signal InventoryItemClicked

InventoryButton.gd

class_name InventoryButton extends Button
var InventoryItem: String:
    set(value):
        InventoryItem = value
        text = value

func _ready() -> void:
    pressed.connect(_on_button_click)

func _on_button_click():
    SomeGlobalFile.InventoryClicked.emit(InventoryItem)

Then in your for-loop that creates the buttons:-

for item: String in ["Sword", "Hammer", "Potion"]:
    var NewButton: InventoryButton = InventoryButton.new()
    add_child(NewButton)
    NewButton.InventoryItem = item

In the scene that listens to inventory signals :-

func _ready() -> void:
    SomeGlobalFile.InventoryItemClicked.connect(_on_inventory_click)

func _on_inventory_click(InventoryName):
    print("Player just picked up a " + InventoryName)

Hope this helps,
Martin

1 Like

A different approach is to connect the button signals when you are making them in the loop, with a bound parameter (see the example in the documentation object::connect).

You could for instance do something like this:

func _ready():
    for i in len(buttons):
        buttons[i].button_down.connect(_button_clicked.bind(i))

func _button_clicked(button_index):
    print("You have clicked button nr %d in the array" % [button_index])

This is useful if you want the code handling the inventory to be in the same script that are creating the buttons.

If you need more functionality to the inventory object however, your inventory script might become too complex, and it would probably be better to create a separate script to put on the button itself like @gridsquat wrote.

Cheers ^^

2 Likes

Thank you both! Tugsav’s idea worked best, but I always appreciate learning more about the system.