[Godot 3] Yield - Is there a way to wait for a function execution ended completely?

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

I want to know if there is a way to use yield() to wait a function to end its execution and then resume the code from where it was called. Cause in the code below, if I comment the yield(get_tree().create_timer(.5), "timeout") line the queue_free() will be executed before the create_explosion function ends.

I just want to execute the create_explosion() function and after that executes the queue_free.

if armor <= 0:
	create_explosion()
	yield(get_tree().create_timer(.5), "timeout")
	queue_free()

Thank you.

1 Like
:bust_in_silhouette: Reply From: Lightnet

Found this answer here: https://forum.godotengine.org/1660/execute-a-function-after-a-time-delay

what if yield is used in a function which is called in update cycle.? does it work ?

Lagger | 2019-07-04 12:24

:bust_in_silhouette: Reply From: Dlean Jeans

Try these steps:

  1. Add a signal, let’s call it exploded
  2. Call it at the end of create_explosion(): emit_signal("exploded")
  3. Replace the yield call
if armor <= 0:
    create_explosion()
    yield(self, "exploded")
    queue_free()

Even better if the explosion is an animation. You don’t need the exploded signal anymore.

if armor <= 0:
    create_explosion()
    yield($AnimationPlayer, "animation_finished")
    queue_free()

Assuming $AnimationPlayer is used to play your explosion.

Thanks man this works very well! There is an animation but the problem is that it is inside of the instantiate explosion (from another scene) inside of the create_explosion() function. In that way I don’t know how to use the animation_finished signal in the parent node.

Here the .gd code attached to the explosion scene:

Note: p_flare, p_smoke and anim (AnimatinPlayer) are childs nodes from the explosion scene.
Note2: the yield($anim, "animation_finished") just works inside of the explosion scene.

extends Sprite

func _ready():
	randomize()
	rotate(deg2rad(rand_range(0,360)))
	$p_flare.emitting = true
	$p_smoke.emitting = true
	$anim.play("fade_out")
	yield($anim, "animation_finished")
	queue_free()

Here is the create_explosion function from the parent node:

func create_explosion():
	var explosion = scn_explosion.instance()
	call_deferred("add_child", explosion)
	emit_signal("exploded_wait")

arthurZ | 2018-02-21 11:50

Shouldn’t this simply be solved by using get_node from the parent node?

yield(explosion.get_node("anim"), "animation_finished")

From the code in your question, this is what we arrive at:

func explode_if_armor_reached_zero(): # or whatever your function name is
    if armor <= 0:
        var explosion = create_explosion()
        yield(explosion.get_node("anim"), "animation_finished")
        queue_free()

func create_explosion():
    var explosion = scn_explosion.instance()
    call_deferred("add_child", explosion)
    return explosion

Dlean Jeans | 2018-02-21 12:59

:bust_in_silhouette: Reply From: justin

You can wait for a function’s completed signal. In your case, it’s

	yield(create_explosion(), "completed")

For a more complete example, consider deal_initial_hands below:

func deal_initial_hands():
	# move_card_from_deck_to_position() ... i.e. run Tween
	yield(get_tree().create_timer(0.25), "timeout")
	print('a')
    # move_card_from_deck_to_position() ... i.e. run Tween
	yield(get_tree().create_timer(0.25), "timeout")
	print('b')
    # etc...

# from call site:
target.deal_initial_hands()
print('x')

If I run the code in call site (which calls deal_initial_hands(), x will print before a and b. So if e.g. you’re relying on values which will be set after deal_initial_hands at call site - then you’re out of luck as they don’t exist yet.

However, you can wait for deal_initial_hands to finish by yielding to it’s completed signal instead of just calling it:

# from call site:
yield(target.deal_initial_hands(), "completed")
print('x')

Now it’ll print a, b, then x.

This answer should be the selected and most voted one, since the ‘completed’ signal is always available for every ‘coroutine’ (the return type when a function yields is actually called GDScriptFunctionState). Take a look at the docs if needed.

https://docs.godotengine.org/en/stable/classes/class_gdscriptfunctionstate.html

gnumaru | 2021-12-27 12:51