What is a good design pattern for confirming a signal was received and processed?

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

Assume we have a board game with the following scene setup

Root

  • Player
  • Board
  • Scoreboard UI

When the Player lands on a space and (say) gets a point, they emit a signal to let the scoreboard know to update, and then proceeds with the rest of its turn:

emit_signal("scoreboard_update", 1)
do_other_stuff()

The Scoreboard UI is then listening for that signal ("scoreboard_update") to update its display. However, say that this updating takes some time (an animation, musical fanfare, etc.) and we want Player to wait for the updating to finish before it proceeds (to do_other_stuff()). Is the best way to accomplish this via waiting for a second signal from Scoreboard UI? As in

emit_signal("scoreboard_update", 1)
yield($"../Scoreboard UI", "scoreboard_updated")
do_other_stuff()

Or, separate out the next action into a separate function connected to the "scoreboard_updated" signal:

func on_Scoreboard_UI_updated():
    do_other_stuff()

…or something else?

:bust_in_silhouette: Reply From: skysphr

If an object emits a signal, it should not be concerned with the matter in which said signal is processed. There could always be one listener, multiple, or none. If you want the player to emit a signal then be frozen until an external factor occurs, you could implement a state system which renders the player frozen indefinitely, and let your controller trigger a state change in the player for resuming activities after the controller is done with whatever it needs to do.

Thanks for the answer. Player actually already has a state machine child node, and you’re right that I could add a WaitingForScoreboard state. However, if I let the scoreboard trigger a state change, couldn’t there be a race condition if the scoreboard acts fast enough? i.e.

  • player emits signal to scoreboard
  • (a)
  • player emits state_change signal to itself
  • (b)
  • player changes state to WaitingForScoreboard

If the scoreboard processes the signal at (a) or (b) and emits back to the player to resume, it won’t be in the correct state at that time. On some related questions, I saw some comments about using call_deferred to avoid this, but I’m a bit fuzzy about how to use it.

bxcr | 2021-09-05 20:24

The player could change states as soon as it emits the scoreboard signal; emitting a signal for self-consumption would eventually trigger a method anyway, so it would make sense to call it immediately instead. If you want to notify other objects of the player’s state change, you could for example add a setter to the state and emit the signal inside the setter.

skysphr | 2021-09-06 01:01