0 votes
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!")
Godot version v3.4.stable.official [206ba70f4]
in Engine by (15 points)

2 Answers

+2 votes
Best answer

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")
by (5,132 points)
selected by

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://godotengine.org/qa/56823/first-argument-of-yield-not-of-type-object

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

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.

+1 vote

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.

by (410 points)
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.