Abstract
- Should the connection be persisted? No: Connect from code.
- Should the connection happen on load? No: Connect from code.
- Should the connection be removed on runtime? Yes: Connect from code.
- Should the connection include a node made on runtime? Yes: Connect from code.
- Are you writing GDScript? No: Connect from code, or use GDScript as glue.
On a reusable asset:
- Should the connection always be there for the asset to work? Yes: Connect from code. No: Connect from the IDE (giving the flexibility to the designer), unless you have one of the reasons above for the asset to connect from code.
Not on a reusable asset: If you have one of the reasons to connect from code, then connect from code. Otherwise, convenience triumphs, which I guess means connecting from IDE.
I will echo that there is no "better" way. They serve different purposes, and there are gray areas.
We could similarly ask what is better between creating nodes from code on creating them in the IDE. The intuition is that you make in from code if it is dynamic. And a similar intuition would apply to connecting signals.
If anything using the IDE will favor a designer workflow over a programmer workflow.
The designer and the programmer can be the same person, taking both roles. The distinction I want to make is on the kind of problems being solved. For the purposes of this answer, let us say that the programmer is creating the pieces that come together to make the game, and the designer is placing those pieces together.
Dividing the roles that way, we have:
The person on a designer role can rely on the connections made on the IDE to be there (they are persisted, and are made effective early when loading the nodes). Also connections made on the IDE give flexibility to the designer (they can be connected in different ways to fit the needs of the game or scenario).
However, for the person on a programmer role, making connection from code is more flexible (they have more control over when the connection happens, and can be made to node created from code). And connections made from the IDE are "optional" (they are a way to give more options to the designer).
But let us talk about differences…
Persisting connections
First of all, connections made in the IDE are persisted in the scene file. Or, rather, I should say the IDE will not create not persisted connections.
From code you can decide to use or not to use the CONNECT_PERSIST
flag. Which could be useful, for example from a tool script (e.g. an addon) to add connection that are later saved by the editor.
Although you probably don't want to do that from the same node being connected, since that code will run again, attempting to re-do the connection.
You can, by the way, save a scene file from GDScript:
var packed_scene = PackedScene.new()
packed_scene.pack(get_node("node_path"))
ResourceSaver.save("res://file_path.tscn", packed_scene)
Addendum: If you want children to be saved along with it, set their owner
property.
Let this be a reminder that the Godot IDE is made on Godot. It is dogfooding. Although it uses the C++ API instead of the GDScript one, GDScript surfaces a lot of the same functionality used to create the IDE.
Thus, we can argue making connections from the IDE is a convenience. See note at the end.
Controlling when the connection is made
Second, since IDE connections are persisted, you don't have control over when they happen. I have gone over the way nodes are loaded here, I just updated it to include signal connection. Connections happen before parenting. To be more precise, they happen outside the scene tree, before NOTIFICATION_PARENTED
(and thus before onready
variables and before Godot calls _ready
), but after Godot calls _init
, runs custom setters.
With code, you can do the connection whenever it is necessary. Thus, using connection from code gives you extra flexibility.
I will remind you that signals are also used with yield
. See Coroutines and signals.
Removing connection on runtime
To remove a connection on runtime, it must be done from code. The IDE has no such functionality.
Your code should not rely on a connection made from IDE being there (you could, for example, remove the connection from the IDE and forget to update the code).
However, it could be intentional, that you can a connection may or may not be there, and if it is there, you want to remove it. IN which case, make sure to check is_connected
.
Otherwise, I would suggest to create connection that will be removed on the same script that removes it.
Connect to nodes created from code
If you create a node from code, it will not show in the IDE, because the node only exist in runtime. And thus, the only way to connect to its signals is from code.
Not GDScript
Connecting from the IDE works flawlessly with GDScript, but not so much with other languages. Depending on the language, you may not have the option, or the IDE might do the wrong thing (C#).
Thus I would not connect a signal from the IDE to a script in another language. Instead I would either connect it from code in that other language, or connect it from the IDE to GDScript, and from there call into the script in that other language.
In fact, I recommend to use GDScript as glue between Godot and other languages. So GDScript will export variables, connect signals, and call into script written with other languages.
Creating a reusable asset (Editable children)
Doing the connections in code means that you know how the scene will be put together when used.
That is, if you are making an asset to be reused, either by yourself or a third party, the code can make less assumptions about the scene where it is used. And it would be inconvenient to require modifying the code to write what to connect. It is a better workflow to simply expose the signals and let the person on the designer role (which could be the same person) connect things as necessary from the IDE.
What can you take for granted from your asset anyway?
If you are using a script/class, you cannot take any assumptions about the scene tree.
If it is an scene you are reusing, you can take for granted the child nodes it has. But never something outside of the scene. That should lead you to the methodology described in Node communication (the right way), which is summarized as "Call down, signal up".
Sometimes it is hard to surface all the relevant options in the root of a scene. Leading us to include the scene, and enabling "Editable Children" in the editor, which will let override the properties of the scene or add new nodes (but not remove).
You should not remove or modify through a scene added with "Editable Children" because the change is taking effect on the original scene.
However, you can add or remove connection made in the IDE. That means that by making the connection in the IDE, you can support scenarios where the connection should not be there.
Thus, for connections attached to a reusable scene, consider: Would the asset work without the connection? Are the scenarios where not having the connection is preferable? In those cases prefer using the IDE to make connection (unless the connection must be made in a way that is only possible from code, in which case you may want to expose the option by other means). Otherwise, make the connection from code.
Note: The connection dialog was improved for Godot 3.2, which is good, but it could be better. See Reworked and more capable ConnectDialog. Due to the current limitations of the dialog, its convenience might not be convenient enough.