Question about the best practice of using custom signals

Godot Version

4.2.1

Question

Hi there! I would like to ask about best practice of signals. I have 2 nodes in UI, where one of these is trying to disable a button from another one using a signal.

I have a script on the first node:

signal button_disabled(is_disabled)

func set_button_disabled(is_disabled: bool):
	resolution_button.disabled = is_disabled

And I have second script on the another node, which is trying to use the signal of the first node (trying to disable a button):

func _ready():
	resolution_node.button_disabled.connect(Callable(self, "set_button_disabled"))

func set_test_button_disabled(is_disabled: bool):
	resolution_node.set_button_disabled(is_disabled)

I’ve noticed, that I can just type “signal button_disabled” without parameters and everything will work fine. And there I have a few questions:

  1. Am I calling a signal from another node in the right way?
  2. Should I use somewhere .emit or emit_signal(…) to call my signal instead of using the name of the function?
  3. Maybe there is any other best ways to connect nodes using signals? (only in code)

Thank you for your answers!

1 Like

I don’t think you are connecting to the signal properly.
If the following is in a script that does not contain the function set_button_disabled() then there will be no connection.

func _ready():
	resolution_node.button_disabled.connect(Callable(self, "set_button_disabled"))

Does your code work as is?
It looks to me like the connection line should read:

func _ready():
	resolution_node.button_disabled.connect(Callable(self, "set_test_button_disabled"))

Yes, the signal should be emitted at the point in code where the disabling event occurs.
It is hard to be more specific without knowing more about the UI structure and flow of your program.

  1. Maybe there is any other best ways to connect nodes using signals? (only in code)

Hard to answer this without desired program flow info.

1 Like

Thank you for your answer!

Yes. I wanted to check exactly how the signals are trying to connect to each other, and therefore I performed an experiment during which I understood that I can name a function in my second node (without a signal) whatever I want, but the name of the function in the first node (with Signal) should be the same, when I’m trying to establish the connection

resolution_node.button_disabled.connect(Callable(self, "set_button_disabled"))

So does it mean, that I should always name the functions between two nodes same, if I want to have a connection with signal from another node?

For me it would be more logical, if we could emit the signal from the first_node and after that something would happen in the second, like this:

func _ready():
	resolution_node.button_disabled.connect(Callable(self, "set_button_disabled"))

func set_test_button_disabled(is_disabled: bool):
	resolution_node.button_disabled.emit(is_disabled)

But it doesn’t seem to work.

I tried also to emit the signal in my second_node like this:

signal button_disabled(is_disabled)

func set_button_disabled(is_disabled: bool):
        button_disabled.emit()
	resolution_button.disabled = is_disabled

but it causes recursion

Could you please show me an example? (even if it’s on github)
I’ve spent a really long time trying to figure out how to communicate using signals, but it’s a little confusing.

– [Common_node] - Just holds two these Nodes together
|–[First_node] – Has a pointer to the Second_node, but hasn’t info about anything inside except of signal and the name of the function
|
|–[Second_node] - Has the Signal, Button and function, which disables the Button in this Node.

In the first Node I have a button(A), which calls set_test_button_disabled(true/false) and disables the button(B) from the second Node

No not at all.
In your post you show a connection string:

resolution_node.button_disabled.connect(Callable(self, "set_button_disabled"))

In this line self is the object and "set_button_disabled" is the function to connect to.
The self refers to the current object ie the script wherein this code is found.
So in order for that connection to work, a function named set_button_disabled must exist in self (the current script)

The signal should be emitted where the event occurred. The point in your code where the button is disabled should also emit the signal button_disabled.
The other node connects to button_disabled and acts on it.

But looking at your code I think the signal is misnamed.
In the first node when the user presses button(A) you want to disable the button(B).
The signal then would be better named signal button_A_pressed().
Then the second node wherein the button gets disabled connects to that signal and acts on it.

resolution_node.menu_item_a_selected.connect(Callable(self, "on_button_a_selected"))   
 ...    
func on_button_a_selected(): 
    button(B).disabled = true

PS: Buttons have built in signals and instead of using coded connection strings you can connect to the button.pressed() signal via the editor. There is no real need for custom signals to act on button presses.

2 Likes

Thank you for your guidance!

I will try experimenting with the code further to better understand the signals and connections.