0 votes

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?

Godot version 3.3
in Engine by (396 points)
edited by

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.

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?.

1 Answer

+2 votes
Best answer

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.

by (189 points)
selected by

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")

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.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.