//rp.wtf

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!