Timer not stopping code. How do I get it to stop where it is?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By soulbreak
extends Node
	
func wait_and_print(new_text):
	yield(get_tree().create_timer(1.0), "timeout")
	print(new_text)

func _on_Button_pressed():
	wait_and_print("Hello")
	wait_and_print("World!")

– Expected behavior –

  • Press Button
  • 1 second passes
  • “Hello” is printed
  • 1 second passes
  • “World!” is printed

– Actual Behavior –

  • Press Button
  • 1 second passes
  • “Hello” is printed
  • “World!” is printed

How do I get wait_and_print() to actually stop in it’s tracks whenever I create a timer?

I can work around this by putting a timer before the function calls, but I don’t see why it won’t work as written.

extends Node
	
func wait_and_print(new_text):
	print(new_text)

# This works but is ugly and cumbersome
func _on_Button_pressed():
	yield(get_tree().create_timer(1.0), "timeout")
	wait_and_print("Hello")
	yield(get_tree().create_timer(1.0), "timeout")
	wait_and_print("World!")
:bust_in_silhouette: Reply From: Inces

line of codes don’t wait for each other to be completed by default. That is why if You create 2 subroutines with yield inside, they are executed right after another, but it only takes a frame, so their timers only have a frame of offset from each other. However when You use yield this means whole FUNCTION stops until yield is not returned. Yield can have various arguments, it doesn’t have to be time. Whatever is argument of yield will stop funtion from execution. What You can do is :

func wait_and_print(text):
        yield(get_tree().create_timer(1.0),"timeout")
        print(text)

func on_button_pressed():
       yield(self.waitandprint("Hello"),"completed")
       yield(self.waitandprint("World"),"completed")

Thanks! This definitely worked to fix my example.

In my actual project I am getting an “First argument of yield not of type object” error. I think maybe because my function is inside a singleton? That’s a problem for another time though. For anyone else who sees this you can take a look at someone else’s example of this error:

https://forum.godotengine.org/56823/first-argument-of-yield-not-of-type-object

Thank you for helping me understand the behavior of the timer!

soulbreak | 2022-01-09 23:44

I know this error all too well as I was having hard time solving it before. I discovered that every yield() must have another yield inside of it as well as “return” line. However my example code should have worked, because yield to complete subroutines have yield to timeout inside of them. Add line “return” after print. In my projects when I want to yield for completion of a function I must add line that yields for tiny amounts of time inside of it.

Inces | 2022-01-10 16:39

:bust_in_silhouette: Reply From: Ninfur

Inces answer seems very reasonable, but if you want some alternatives there is a popular thread over here explaining a few different methods of delaying function execution. Including using timers and tweens.

If you really want to stop the programs execution, you could also use OS.delay_msec(1000), but I would not recommend this. Nor will it result in the behavior you are expecting, because I believe even the print flush is delayed.