Yield doesn't resume when the signal is emitted

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

I’m using a yield inside of a function like this:

unit.play_turn(action)
yield(unit,"action_finished")
next_unit_in_queue()

But the code after the yield never gets executed even though the signal is being emitted.
I created a function connected to this signal to check and it is called at the right time, but the yield doesn’t break I have used yields in this manner before and never encountered this problem? Does anyone have any ideas of what may be causing this?

You may want to post test code that fails so people can bring it into the IDE. Would be easier for people to spot a problem. E.g. maybe the signal name is wrong. Right now it’s a guessing game.

wyattb | 2021-06-18 12:48

Sorry I fixed it yesterday but I actually didn’t change anything about the signals just cleaned the code around these functions. At the time I created a function connected to this signal and it worked so the name of the signal is right, using print I got this output:

#BattleManager.gd

func create_unit():
  var unit :Unit = Unit_scn.instance()
  unit.connect("action_finished", self, "action_finished_foo")

func action_finished_foo():
  printerr("action_finished signal received")

func turn_preparation(unit):
  printerr(" - turn_preparation - ")
  unit.play_turn(action)
  yield(unit,"action_finished")
  print("yield resumed")
  next_unit_in_queue()

func next_unit_in_queue():
  printerr(" - next_unit_in_queue -")

#Unit.gd

func play_turn(action):
#  I commented everything else just to test the signal
  emit_signal("action_finished")

The output looked like this:

 - turn_preparation -
action_finished signal received

So I knew I didn’t write the signal name wrong and that it was emitted at the right time.
but the yield didn’t resume.

I would’ve liked to share the project but its private and I couldn’t reproduce it again to create a example project after the fact, but that output is weird right?.

IHate | 2021-06-19 07:00

:bust_in_silhouette: Reply From: Andrew Wilkes

I found that yield returns from the function if it receives a signal emitted within the current frame. So in this case it doesn’t continue to the next statement. Using call_deferred, you can delay the emission of the signal to at least the next frame.

wow! You are right. Is there something about this on the documentation? and is that the intended behaviour? Without call_deferred or waiting for the next idle frame before emitting the signal Yield will return.
So before I implemented the animations the signal was emitted in the same frame and thus yield returned instead of resuming. Thanks a lot.

Small test:

func _ready():
	connect("button_down",self,"_on_button_pressed")
	foo_test()

func foo_test():
	print("foo_test")
#	call_deferred("foo_emit")
	foo_emit()
	yield(self,"foo")
	print("yield resumed")
	foo_print()

func foo_emit():
	print("foo_emit")
#   yield(get_tree(),"idle_frame")
	emit_signal("foo")

func foo_print():
	print("success")

IHate | 2021-06-19 08:49

It’s not mentioned in the Docs. I discovered it when implementing tests on my code where the tests were actioning faster than a human could do things. I guess that most people will not encounter this problem though.

Andrew Wilkes | 2021-06-25 10:29

:bust_in_silhouette: Reply From: andlip

Let me dig up this thread as it was a top google search for problems with yield and self emitted signal.

The thing I missed (as a Godot newbie) was that I had to connect signals in the inspector:

  • between self and self
  • between self and it’s child nodes

For some reason I assumed that signals are connected to emitters, and that child nodes are also connected to the parent node, by default.

Hope that saves somebody a bit of time :slight_smile: