+1 vote

I am trying to get a Timer to fire at a set interval, to be used in a progress bar whilst rescaling large images. All the other code works, but the Timer does not seem to fire whilst the CPU is busy processing an image.

As an example, in the sample code below, I was expecting the Timer callback to be executed whilst the for-loops are busy.

extends Node
var time_waster: float
var duration: float = 0.0
var timer: Timer

func _ready():
    timer = Timer.new()
    timer.set_wait_time(0.1)
    timer.autostart = false
    add_child(timer)

    var _error = timer.connect("timeout", self, "_timeout")

    print("Start")
    timer.start()
    for j in range(1,20):
        print("J Loop----------------- ", j)
        for i in range(1,2000000):
            time_waster = log(i*j) # Waste some time

    timer.stop()
    print("End")

func _timeout():
    duration += timer.wait_time 
    print("Timer call back: ",duration)

But the output when running the above code is ...

Start
J Loop----------------- 1
J Loop----------------- 2
etc. until
End

The Timer does not fire at all whilst the loops are running ?

I do not see what I am doing incorrectly. Any help appreciated.

Thanks

Godot version 3.3.stable
in Engine by (18 points)

1 Answer

0 votes
Best answer

I think because of all the calculation you are doing you're not hitting an idle frame allowing the timer to increment. From the docs:

enum  TimerProcessMode:
TIMER_PROCESS_PHYSICS = 0
Update the timer during the physics step at each frame (fixed framerate processing).

TIMER_PROCESS_IDLE = 1
Update the timer during the idle time at each frame.

For what you're doing you should probably just use a TextureProgress node and update it at the top of your for loop.

var progress_bar = TextureProgress.new()
self.add_child(progress_bar)
progress_bar.max_value = num_things_to_load
for i in range(num_things_to_load):
    progress_bar.value = i
    do_work_here()
by (3,707 points)
selected by

Thank you for your answer. I had misunderstood when timers were called, thinking that they were events that ocurred independently of the process load.

I solved my problem by implementing the compute intensive part in a separate thread. The code below works as I originally was expecting, with an output of the form ..

Starting thread
Start loop
1
2
Timer: 0.1
Timer: 0.2

...
...

9
Timer: 1.9
Timer: 2
Timer: 2.1
End loop
Timer: 2.2
Thread complete
END

 extends Node

    var load_time: float
    var timer: Timer
    var thread: Thread
    var compute_complete: bool
    signal thread_complete

    func _ready():
        load_time = 0.0

        timer = Timer.new()
        timer.set_wait_time(0.1) 
        add_child(timer)    
        var _error = timer.connect("timeout", self, "_on_Timer_timeout")
        timer.start()

        print("Starting thread")
        thread = Thread.new()
        thread.start(self,"_compute_function")
        yield(self,"thread_complete")
        print("Thread complete")

        timer.stop()
        print("END")

    func _compute_function(userdata):
        compute_complete = false
        print("Start loop")
        for j in range(1,10):
            print(j)
            for i in range(1,6000000):
                var result = log(i*j)
        print("End loop")
        compute_complete = true

    func _on_Timer_timeout():
        load_time += timer.wait_time 
        print("Timer: ",load_time)
        if compute_complete:
            thread.wait_to_finish()
            emit_signal("thread_complete")
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.