How to interrupt program flow to modify UI settings

Godot Version

4.2.2

Question

I’m writing a program that generates multiple spherical meshes with thousands of vertexes that would benefit from feedback to the user so they don’t think the program has halted when it is actively working.

To achieve my goal I am accessing the panel container node and applying a styleboxflat with the border color set to various colors to indicate the status of each mesh (red for pending processing, green for completed processing, and black to indicate that all processes have completed). What I’m finding is that the whole block of code executes and the panel container border color doesn’t update until everything else has completed

In the spirit of trying everything I applied the styleboxflat and then created a timer node that I have run for .001 seconds with an ‘await timer.timeout’ instruction immediately following. Doing this sets the border color before the program advances to the heavy work of crunching thousands of vertices. What I’m looking for is a solution that is a tad more elegant, or at least an understanding of why the timer is necessary.

func _on_generate_spheres_pressed():
	for i in range(Global.noise_spheres):
		var panel = Global.noise_sphere_panel_containers[i]
		var stylebox = StyleBoxFlat.new()
		stylebox.set_border_width_all(4)
		stylebox.set_expand_margin_all(4)
		stylebox.set_corner_radius_all(20)
		stylebox.border_color = Color(.75, .25, .25)
		panel.add_theme_stylebox_override("panel", stylebox)
	
		var timer = Timer.new()
		timer.wait_time = 0.01
		timer.one_shot = true
		add_child(timer)
		timer.start()
		await timer.timeout

	for i in range(Global.noise_spheres):
		Global.current_noise_sphere = i
		
		var noise_sphere_script = load("res://gui_noise_sphere.gd").new()
		noise_sphere_script.update_fast_noise_lite_parameters()
		noise_sphere_script.generate_noise_sphere_mesh_instance_3d()

	var summary_sphere_script = load("res://gui_summary_sphere.gd").new()
	summary_sphere_script.update_summary_sphere_mesh()

If you run your code on the main thread it will block the thread until your code is executed (and blocking the main thread will basically freeze the game) , that’s normal.

A simpler way of doing what you did is
await get_tree().process_frame
This will wait until the next frame, basically let all the other code run once then continue.

If you don’t want to “take a break” every loop cycle you can do something like:

if i % 10 == 0: # true every 10th loop
    await get_tree().process_frame

Or you can look into running this code in a sub thread to avoid blocking the main thread, but I’m not really an expert on that so can’t really help with that:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.