godot 4 signal function parameter not in scope

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By cortey

How do I connect this button so that when I press it, it calls “sort_items” function?

Structure of inventory.tscn for reference is:

-Inventory (PanelContainer) #has script inventory.gd
    -VBoxContainer
        -MarginContainer
            -ItemGrid
        -SortButton (Button)

This is relevant part of inventory.gd

extends PanelContainer

@onready var sort_button = $VBoxContainer/SortButton
signal sort_clicked()

func _ready():
	sort_button.pressed.connect(sort_items) #this doesn't work

func sort_items(inventory_data: InventoryData):
	#sort code will reference inventory_data
	pass

func _on_sort_button_pressed():
	#sort_items(inventory_data) #this doesn't work 
	emit_signal("sort_clicked")

_on_sort_button_pressed is connected from the editor.

I have also tried to do

sort_button.pressed.connect(sort_items(inventory_data))

but it throws error: inventory_data not in scope, which makes sense.

inventory_data.gd contains

extends Resource
class_name InventoryData

#some functions

Please let me know if additional background information is needed to help. I will try my best to explain.

:bust_in_silhouette: Reply From: popcar2

You can’t add parameters to signals that don’t have them. Button.pressed can’t hold inventory_data, you should make your own signal and have that be emitted and connected to other scripts. I’m going to assume you want sort_clicked to call sort_items, and your InventoryData is inside of sort_button, right? Let your button send the signal to your parent, and have it handle the click itself.

So for your example:

inventory.gd

extends PanelContainer

@onready var sort_button = $VBoxContainer/SortButton

func _ready():
    # this should work, because sort_clicked expects InventoryData
    sort_button.sort_clicked.connect(sort_items) 

func sort_items(inventory_data: InventoryData):
    # Sort stuff coming in from the button
    pass

sort_button.gd

extends Button

signal sort_clicked(inventory_data: InventoryData)

var inventory_data: InventoryData # create one however you'd like

# Connect it from the inspector
func on_pressed():
    sort_clicked.emit(inventory_data) 
    # This sends inventory_data to to Inventory.gd, which will run sort_items()

inventory_data is in a parallel class called InventoryData. inventory.gd linked to inventory.tscn is able to communicate with inventory_data.gd with signals. The button is a child within the inventory.tscn. when the button is clicked I want to act on the inventory data but it is not in scope
Maybe I can’t do this directly with the button, but could I still use it as a trigger somehow to fire a setter function which can act on inventory data? Sorry I’m not really sure how this works.

cortey | 2023-04-23 17:18

Where is inventory_data going to be stored? Is it a variable in inventory.gd?

popcar2 | 2023-04-23 17:27

inventory_data is a Resource currently stored in testInv.tres. InventoryData is an array of type SlotDatas

cortey | 2023-04-23 18:38

You can use an Autoload if you need persistent data that’s easy to access and isn’t scene-dependant. Otherwise, you could send a signal to request stuff from another node and then receive another signal with whatever data you need. or you could always just reference a node and get the variable directly.

If you need it to happen with signals, you could have your inventory emit request_inventory_data signal on button press, then have your testInv.tres receive the signal and emit sort_clicked(inventory_data), then have your inventory do whatever with the signal.

Again, that’s a little complicated. Is there anything stopping you from just getting the variable directly like test_inv.inventory_items?

popcar2 | 2023-04-23 22:02