Conditional processing in Godot
Mon Apr 27 2026
The issue
When you define the _process function in your Godot script, the engine calls it on every frame. 99.9% of the time it's what you want anyway, but what about the remaining 0.01%?
For example, the default script template for Godot comes with an empty _process function:
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
If you don't clear it, the nodes to which this script is attached will just happily execute it on every single frame.
No big deal, if there's just a single node like this. But what if there are a hundred, a thousand, or more? It will compound. This was an observation Paul Lawitzki highlighted in his GodotFest 2025 talk A Peek Under the Hood: Technical Learnings from Halls of Torment. Since they can have so damn many enemies on the map in Halls of Torment, they can't have their process function running at all times, so it's being conditionally turned off. To do that yourself, all you need to do is call set_process(should_process) on the node where should_process is true or false, depending on if you need the _process() function to execute.
Avoiding busy-waiting
Let's use an example of a node that processes unless it's sleeping property is true:
var sleeping: bool = false
func _process(delta: float) -> void:
if sleeping:
return
do_stuff()
func wake_up() -> void:
sleeping = false
func tranquilize() -> void:
sleeping = true
Now the node won't call do_stuff() when sleeping is set to true. If we need do_stuff() called, we just set sleeping to false. The downside, though, is that, while sleeping is true, the node is essentially busy-waiting since the _process() function is still being called, and while it's returning early, the call itself is making the CPU do work. We can avoid that very simply:
func _process(delta: float) -> void:
do_stuff()
func wake_up() -> void:
set_process(true)
func tranquilize() -> void:
set_process(false)
Now we got rid of the sleeping variable entirely, and cleaned up the _process() function! After calling tranquilize(), the _process() function won't be called anymore until wake_up() is called. As a side note, if you want to check what you could have checked with the sleeping variable, you can just use is_processing().
Obviously, you can also stop processing within the process function itself. Here's an example of a countdown:
var _remaining: float
func _ready() -> void:
set_process(false)
func _process(delta: float) -> void:
_remaining -= delta
if _remaining <= 0:
# countdown done
set_process(false)
func start(time_sec: float) -> void:
_remaining = time_sec
set_process(true)
The only thing we have to keep in mind is to disable processing right away (see the _ready function), otherwise whatever's executing when the countdown finishes will execute in the beginning as well.
If you want to do this with physics processing, you can use set_physics_process() instead.
Conditional input handling
You can extend this approach to input handling too.
As an example, The Rise of the Golden Idol has this type of code in a couple places:
func _unhandled_input(event: InputEvent) -> void:
if not visible:
return
stuff()
This means that even if the node is invisible, it continues receiving unhandled input events, all of which are then dismissed. Wasted processing. It could be improved by doing it this way:
func _ready() -> void:
visibility_changed.connect(
func() -> void:
set_process_unhandled_input(visible)
)
func _unhandled_input(event: InputEvent) -> void:
stuff()
We replaced the condition with a bit of setup code, which will make sure that _unhandled_input() isn't even called when the node is invisible.
It's not just unhandled input you can toggle. Godot has methods for toggling all kinds of input-related stuff - set_process_input(), set_process_shortcut_input(), set_process_shortcut_input(), set_process_unhandled_key_input() and the aforementioned set_process_unhandled_input().
Conclusion
This should give you an extra frame or two, especially if you're making something like an action rogue-lite or bullet hell game with many things on the screen otherwise it just makes your logic a bit cleaner, which is a pretty good thing on its own!
If you want to talk about this kind of stuff or add a tip of your own, you can reach me on bsky or mastodon!