How do I pause code (like time.sleep in Python)?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By disorientedperson
:warning: Old Version Published before Godot 3 was released.

Using GDScript, I have a separate thread where certain things in my game are being done. This needs to involve pausing that thread for a certain amount of time. I’m looking for something equivalent or similar to Python’s time.sleep function.

I apologize if this is obvious; I’m brand new to Godot. Thanks!

:bust_in_silhouette: Reply From: avencherus

yield() and resume()

or you can use signals in yield()

The standard example is:

yield(get_tree(), "idle_frame")
:bust_in_silhouette: Reply From: ericdl

The OS object has functions delay_msec and delay_usec that will delay executing of the current thread by given milliseconds and microseconds, respectively. Probably not a good idea not to use them on the main thread obviously.

Also, Godot 2.2+ will introduce a simple way to pause code execution for x amount of time.

In the meantime, you can use a timer with yield statement to pause for x amount of time.

For example:

signal timer_end

func _wait( seconds ):
	self._create_timer(self, seconds, true, "_emit_timer_end_signal")
	yield(self,"timer_end")

func _emit_timer_end_signal():
	emit_signal("timer_end")

func _create_timer(object_target, float_wait_time, bool_is_oneshot, string_function):
	timer = Timer.new()
	timer.set_one_shot(bool_is_oneshot)
	timer.set_timer_process_mode(0)
	timer.set_wait_time(float_wait_time)
	timer.connect("timeout", object_target, string_function)
	self.add_child(timer)
	timer.start()

To use, call _wait(1.5) anywhere you need to introduce a pause.

I tried to do something like this:

onready var timer1 = get_node("Timer1")

func run_timer(time):
	timer1.set_wait_time(time)
	timer1.set_timer_process_mode(0)
	timer1.start()
	yield(timer1, "timeout")
	print("Timer is done!")

func test_anim():
	run_timer(5)


func _ready():
	
	test_anim()
	
	print("Print after test_anim function is ended!")

I got “Print after test_anim function is ended!” and then, after 5 seconds “Timer is done!”.
But but how I could get this events being done step-by-step?
Wait until the timer would end and then do the rest?

Aeons | 2016-11-06 16:07

Your function run_timer() prints “Timer is done!” before the timer is finished. Also, if you want a pause inside func _ready() then the yield should be there.

Try this modified code, note the connection of the variable signal timer_end:

onready var timer1 = get_node("Timer1")
signal timer_end


func run_timer(time):
	timer1.set_wait_time(time)
	timer1.set_timer_process_mode(0)
	timer1.connect("timeout",self,"_emit_timer_end_signal")
	timer1.start()
	print("Timer is created")


func _emit_timer_end_signal():
	emit_signal("timer_end")


func test_anim():
	run_timer(5)


func _ready():
	test_anim()
	yield(self, "timer_end")
	print("Print after test_anim function is ended!")

ericdl | 2016-11-06 20:55

Edited the answer to include the variable signal timer_end, it should have been there originally, my apologies

ericdl | 2016-11-06 20:58

Er… Yes. It’s still a bit bulky. So if need to call run_timer() function in test_anim() twice, I have to write something like this:

onready var timer1 = get_node("Timer1")
signal timer_end


func run_timer(time):
	timer1.set_wait_time(time)
	timer1.set_timer_process_mode(0)
	
	timer1.start()
	print("Timer is created")


func _emit_timer_end_signal():
	emit_signal("timer_end")


func test_anim():
	run_timer(5)
	yield(self, "timer_end")
	print("Do something 1")
	run_timer(5)
	yield(self, "timer_end")
	print("Do something 2")


func _ready():
	timer1.connect("timeout",self,"_emit_timer_end_signal")
	test_anim()
	yield(self, "timer_end")
	yield(self, "timer_end")
	print("Print after test_anim function is ended!")

And the more times I call run_timer(), the more yield(self, "timer_end") I need to add.
Is there a way to make the code shorter?

Aeons | 2016-11-06 21:11

Thanks for the thorough answer!

disorientedperson | 2016-11-06 23:14

@Aeons
The timer/yield is meant to introduce a timed delay inside the function in which it is called. So I am not sure what you are trying to achieve with your code between _on_ready() and test_anim().

If you are testing animations with a AnimationPlayer, you can yield to signals generated by the AnimationPlayer per the documentation:

# Resume execution when animation is done playing:
yield( get_node("AnimationPlayer"), "finished" )

If you are using yield with the expectation of delaying execution of your code as it passes between functions, simply emit a seperate signal at the end of the called function. In this case, emit a new signal at the end oftest_anim() and wait for it in _ready():

onready var timer1 = get_node("Timer1")
signal timer_end
signal test_anim_end

func run_timer(time):
	timer1.set_wait_time(time)
	timer1.set_timer_process_mode(0)
	timer1.start()
	print("Timer is created")

func _emit_timer_end_signal():
	emit_signal("timer_end")

func test_anim():
	run_timer(2)
	yield(self, "timer_end")
	print("Do something 1")
	run_timer(2)
	yield(self, "timer_end")
	print("Do something 2")
	emit_signal("test_anim_end")

func _ready():
	timer1.connect("timeout",self,"_emit_timer_end_signal")
	test_anim()
	yield(self, "test_anim_end")
	print("Print after test_anim function is ended!")

ericdl | 2016-11-07 01:06

If you are using yield with the expectation of delaying execution of your code as it passes between functions, simply emit a seperate signal at the end of the called function.

Yes, that one.
It seems, it can’t be done without a new signal.
Thanks for the explanations.

Aeons | 2016-11-07 07:28