Is it possible to start a timer only once in _process()?

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

I have a command in physics process that checks how many enemies in a group there are, and if the number is equal to 0, it should start a timer. The issue is, since it’s in delta, it starts the timer every frame. I need a way to check every frame how many enemies are left, but then start a timer once it reaches 0. I’ve tried setting a bool to true instead, but I don’t really have a place to start the timer. I can’t just call a separate function with the start command in it, because it would still be called every frame. I’d appreciate some help with this :frowning:

:bust_in_silhouette: Reply From: Mougenot

I think your idea with a boolean works just fine. The following example script is with a minimal scene containing a Node as the root with a child Timer Node called Timer. Timer Node also has the signal timeout() connected to _on_Timer_timeout() in Node´s script. enemies_left() serves as a placeholder for your mentioned function.

extends Node

var timer_inactive = true

func _ready():
	$Timer.one_shot = true
	
func _physics_process(_delta):
	if timer_inactive and enemies_left() == 0:
		timer_inactive = !timer_inactive
		$Timer.start()

func enemies_left():
	return 0
	
func _on_Timer_timeout():
	#do stuff
	timer_inactive = true

Make sure oneshot is enabled in your Timer Node. By evaluating timer_inactive before enemies_left(), enemies_left() is only called when timer_inactive is true

:bust_in_silhouette: Reply From: Ellye

You do as you thought - you set a bool to see if the timer was already called.

Something like, to keep it simple:

var timer_already_called := false

func _process(delta: float) -> void:
	if (not timer_already_called 
    and check_number_of_enemies_in_group() == 0):
        start_timer()
        timer_already_called = true
   

If you’re worried that running a code like that every frame would hinder performance due to the counting of objects in a group even after you don’t need it anymore, don’t be: just order the conditions in the IF statement to check the variable first and count the group after.

(Since the IF is an AND statement, as soon as any condition returns false it doesn’t need to keep evaluating the rest of the conditions - the end result is already false, so it won’t cause any performance issue.)