hello

i've been using godot for a while now, i love it! best engine ever!
but i've never really got my head around signals, i kinda know how to use them
but i don't get the point

a signal is a soft coupling so it doesn't break the game when the connecting object gets destroyed, but... in the receiver code you have to reference the emitter node by

emitter.connect("customsignal", self, "adjustand_print")

but that's a coupling cause you need the find and reference the emitter with

var emitter = getparent().getnode("signal_emit")
if this line fails then the game breaks anyway!

unless the receiver is a child, or a parent of the emitter, in which case i could do this
instead

$receiver.adjustandprint() or .../ect...

and if not a child or parent then i might as well do this

var receiver= getparent().getnode("receiver")
receiver.adjustandprint()

why can't i just do this?
connect("customsignal", self, "adjustand_print")

if one node is emitting then surely receivers listening can react?
or have i got it all wrong?

any help or enlightenment would be great!
thanks

oh and ps. i do know that you can connect via the editor it does solve a shed load of the above but i would like the option of doing in code. or i could use the get node, or find by group.

  • JusTiCe8 replied to this.
  • [This applies to Godot 3.x. Signals have changed in Godot 4.x.]

    I'm not sure if this answers your question, but to make using signals easier, I created an autoload named Events with script events.gd. Here's a template for the script:

    extends Node
    
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_1
    
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_2
    
    # Parameters
    #	param1 (Type) - Description.
    #	param2 (Type) - Description.
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_3(param1, param2)
    
    # Each of the signals declared above can be connected by calling this method.
    # Typically the caller is the target, which passes "self" for that parameter.
    # The return value of this method is enum Error.
    func connect_signal(_signal: String, target: Object, method: String,
    		binds: Array = [], flags: int = 0) -> int:
    	return connect(_signal, target, method, binds, flags) 

    Example of connecting a signal:

    #warning-ignore:RETURN_VALUE_DISCARDED
    Events.connect_signal("example_signal_1", self, "_on_example_signal_1")

    Example of emitting a signal:

    Events.emit_signal("example_signal_1")

    [This applies to Godot 3.x. Signals have changed in Godot 4.x.]

    I'm not sure if this answers your question, but to make using signals easier, I created an autoload named Events with script events.gd. Here's a template for the script:

    extends Node
    
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_1
    
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_2
    
    # Parameters
    #	param1 (Type) - Description.
    #	param2 (Type) - Description.
    #warning-ignore:UNUSED_SIGNAL
    signal example_signal_3(param1, param2)
    
    # Each of the signals declared above can be connected by calling this method.
    # Typically the caller is the target, which passes "self" for that parameter.
    # The return value of this method is enum Error.
    func connect_signal(_signal: String, target: Object, method: String,
    		binds: Array = [], flags: int = 0) -> int:
    	return connect(_signal, target, method, binds, flags) 

    Example of connecting a signal:

    #warning-ignore:RETURN_VALUE_DISCARDED
    Events.connect_signal("example_signal_1", self, "_on_example_signal_1")

    Example of emitting a signal:

    Events.emit_signal("example_signal_1")

      Sparrow the documentation will help you understand better the logic. It's may take quite some time to fully understand !

      Signals doesn't mean you have to maintain a hard link or a tether between parts of your code, it's a way to communicate without knowing which is where.
      Node/sub-scene emit signals
      Parents in the tree can deal with them or not, you can either connect the signal statically using the editor or dynamically by code.

      I mean if you design a sub-scene ready-to-use for a UI, you may have health, score, items in an inventory (current weapon), ammo, ...
      You're free to use your UI scene in many games, but not using all its features, like a game without ammo or items to pick/use, signal will just be some place-holder, you may later remove for optimization purpose.

      And by the way, coming from Unix OSes, I saw signals as tiny communication mean, but Godot allow to pass variables to handler(s), which make them very powerful.

      Hope this will give you some answers.

        DaveTheCoder

        cheers, i did see this way of doing, thanks for the code
        looks quite a clean way to do it, especially if you're using a global
        to keep play stats ect.

        i'll try in the future

        thanks

        JusTiCe8

        cheers for the answers, and it's not a negative to what you have said, but like i said, i still don't really see the benefit of using signals

        I mean if you design a sub-scene ready-to-use for a UI, you may have health, score, items in an inventory (current weapon), ammo, ...
        You're free to use your UI scene in many games, but not using all its features, like a game without ammo or items to pick/use, signal will just be some place-holder, you may later remove for optimization purpose.

        if i have a UI node with these other nodes i might as well use $score, $items ect...

        if i have to reference the UI at some ANY point, then i've created a coupling

        There has to be a coupling, or else there is no connection, the signal wouldn't know where to go.

        It's basically a message system, producer / consumer, server / client, publisher / subscriber. So there is always some connection.

        However, you can build systems on top of signals to make them more generic, like with Singletons / Autoloads.

          Regardless, there has to be a connection. Like there is a signal "button_up". Which button was up? If you have multiple buttons and they do different things it won't work.

          That's not a good example. The button's node reference or other identification can be passed as a signal parameter.

            Sure, but then you'd have potentially every node checking every single signal and having an if statement or match to see if it is relevant. That doesn't sound efficient.

            DaveTheCoder The button's node reference or other identification can be passed as a signal parameter.

            And this would be coupling, as you'd have to code the id number in somewhere. Just kicking the can down the street.

            thanks guys, understood.
            i was just fishing to see if there was a better way, agreed, there has to be a connection and it was lazy of me to think there wouldn't be... without cost anyway....
            i'll get back to it now, i suppose it's simple really, the writer of the code needs to keep track of the objects/nodes in play and know when they need updating of if they
            get destroyed counter this, by writing code to guard/cover all outcomes.

            thanks again

            Well signals are the base. You can build structures around them. If you use an Autoload, it is accessible everywhere, and you can send and receive signals in that one place.

            But then you would be responsible for tracking which objects are what, like using some id system like @DaveTheCoder suggested.

              cybereality If you use an Autoload

              In my reply above, I provided an example of using an autoload. My only gripe is that I have to declare the signals in the autoload, since they're emitted through that class. Ideally, I would like to (somehow) avoid that. Can you think of a way of doing that?

              I haven't played with signals in 4.0, and don't know if that provides a solution.

              Please use "4.0" in the link instead of "stable". "Latest" and "stable" are confusing terms these days. 😉

              That's just where google took me, but good point.