Problem handle yield

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

Well here is the problem I have a function to implement a very very simple wander in a kinematic body, the question is that I program it as follows

func _do_wander():
    wander_timer.wait_time = rand_range(1, wander_time)
    wander_timer.start()
    yield(wander_timer, "timeout")
    print_debug("Change Direction?")
    var random_direction = [Vector2.RIGHT, Vector2.LEFT]
    random_direction.shuffle()
    velocity.x = random_direction[0].x * wander_speed

It seems logical to me, I mean I program a random time so that it is not so monotonous and I start the timer then I do a yield to wait for the function to send the timeout signal …
And the editor ignores me and keeps running often, so I ran out of the wander, but I have a nice shake effect on the body to which I apply it :smiley:
After a while manipulating and testing things I achieved the effect I wanted by moving the yield to the beginning of the function:

func _do_wander():
	yield(wander_timer, "timeout")
	wander_timer.start()
	[...]

of course the console tells me that the function is running non-stop, which is not true? since in the remote tab and in the game I am having everything as I wish.

Does anyone know what happens?

:bust_in_silhouette: Reply From: timothybrentwood

yield() immediately returns you to the function that calls _do_wander() then once it gets the timeout signal it drops back into _do_wander() at your print_debug() statement. If you are calling this from _process() or _physics_process() you’re probably just creating a huge call stack of _do_wander() function calls since your wander_timer.wait_time is always longer than the time between frames.

The more appropriate way to handle this behavior would be to just handle this logic in the callback for the timeout signal of your Timer:

onready var wander_timer = $Timer # or whatever your path is

func _ready():
    wander_timer.connect("timeout", self, "_do_wander")
    wander_timer.one_shot = true
    _do_wander()

func _do_wander():
    print_debug("Change Direction?")
    var random_direction = [Vector2.RIGHT, Vector2.LEFT]
    random_direction.shuffle()
    velocity.x = random_direction[0].x * wander_speed
    wander_timer.wait_time = rand_range(1, wander_time)
    wander_timer.start()

This ensures there’s only ever one call to _do_wander() queued to execute at any given time.

More about how yield() works:

Thank you, now I understand what is happening

Ahotenus | 2021-08-12 11:34