Introduction: Why This Distinction Matters
Everyone who starts building with Godot Engine meets _process and _physics_process early on. And most people run into problems like "the character moves faster on a beefier PC," "movement looks choppy," or "sometimes objects pass through walls."
Almost all of these come from not understanding the roles of _process and _physics_process and putting logic in the wrong place. This article breaks down the difference between the two functions at the heart of Godot's game loop.
What You'll Learn
- The difference in how they're called:
_process(variable) vs_physics_process(fixed)- Using delta correctly so game speed doesn't change with PC performance
- A character movement pattern that separates input, physics, and visuals
- The physics interpolation setting that eliminates jitter
_process vs _physics_process: The Core Differences
The most important difference between the two functions is when and how often they're called. This maps directly onto the game development concepts of "variable timestep" and "fixed timestep."
| Aspect | _process(delta) | _physics_process(delta) |
|---|---|---|
| When it's called | Every frame (every draw) | At a fixed interval (every physics step) |
| Timestep | Variable | Fixed |
| Call frequency | Depends on PC performance and load (e.g. 60 FPS, 144 FPS) | Depends on project settings (default: 60 times/second) |
The delta argument | Elapsed time since the previous frame (varies) | Time between physics steps (constant) |
| Main uses | UI updates, input polling, visual effects, non-physics animation | Physics, collision detection, timing-critical logic |

_process: called every time the screen updates, so it suits anything visual. Its interval is unstable, though, which makes it unsuitable for precise work like physics._physics_process: called at a constant interval regardless of frame rate, which guarantees reproducible physics-based movement (the same result no matter when or on whose machine it runs).
Here's the mental model: the parts players see and touch belong in _process, and the physical laws of the game world belong in _physics_process. When in doubt, come back to that mapping.

Common Mistakes and Best Practices
Understanding the theory doesn't stop you from slipping up in practice. Here are specific mistakes paired with the best practices that fix them.
| Common Mistake | Best Practice |
|---|---|
Running physics (move_and_slide) in _process.→ Behavior becomes frame-rate dependent and unstable. | Always run physics in _physics_process.→ You get reproducible, stable physics behavior. |
Adding values in _process without using delta.→ Game speed changes with PC performance. | Always multiply by delta for time-based work in _process.→ You get a uniform speed independent of frame rate. |
Polling input (Input.is_action_pressed) in _physics_process.→ Inputs get dropped and controls feel sluggish. | Poll input in _process or _input and store the result in member variables.→ Input is detected every frame, which feels smooth. |
Updating visuals (UI, effects) in _physics_process.→ It doesn't sync with rendering, which causes jitter. | Do visual work in _process.→ It syncs with the draw frame for smooth visuals. |
Here's what delta does, as a diagram. Because per-frame movement is automatically scaled by speed * delta, the distance covered in one second is the same at high FPS and low FPS.

Practical Code: Character Movement
Let's look at character movement code that follows these best practices. The key is properly separating input, physics, and animation.
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
# Gravity as computed by the physics engine
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var input_direction = Vector2.ZERO
var jump_requested = false
# 1. Input: runs every frame and only stores input into variables
# _input() works too, but _process is more intuitive for continuous input
func _process(delta):
# Read horizontal input
input_direction.x = Input.get_axis("move_left", "move_right")
# Jump input is only recorded as a flag (physics applies it in _physics_process)
if Input.is_action_just_pressed("jump"):
jump_requested = true
# Visual work (e.g. updating animation)
update_animation()
# 2. Physics: runs on a fixed timestep
func _physics_process(delta):
# Apply gravity
if not is_on_floor():
velocity.y += gravity * delta
# Consume the stored jump input here
if jump_requested and is_on_floor():
velocity.y = JUMP_VELOCITY
jump_requested = false
# Set horizontal velocity from the input direction
velocity.x = input_direction.x * SPEED
# Run the physics
move_and_slide()
func update_animation():
# Put visual code here, such as updating the animation tree
pass
In this code, _process handles smooth input detection and animation updates, while _physics_process focuses on stable physics (gravity and movement). The key point is that jump input is "recorded" in _process and "consumed" in _physics_process. Physics state like velocity is only modified inside physics steps. Keep that separation and you avoid dropped inputs and unstable physics at the same time.
Performance and Advanced Topics
Smoother Motion with Physics Interpolation
When physics runs at 60 times per second but rendering runs at 144, the difference in frequency makes objects look choppy. That's jitter, and physics interpolation solves it.
Enable this feature and the engine automatically interpolates positions between physics steps, drawing them smoothly on render frames.
- How to enable: turn on
Project Settings > Physics > Common > Physics Interpolation.
For games where the camera follows a character, this setting is essentially mandatory.
Input in _input() vs _process()
Besides using Input.get_axis() inside _process(), you can handle input through the _input(event) callback.
_input(event): called the moment an event occurs, such as a mouse click or key press. It suits one-shot actions (opening an inventory, firing a weapon)._process(): better for checking continuous state. Movement code that checks "is the key still held down" withis_action_pressed()is more intuitive here.
Both are valid; using each for its intended role makes your code's intent clearer.
Summary and Next Steps
Choosing correctly between _process and _physics_process is one of the first and most important steps in Godot development. Get into the habit of asking yourself: "does this need physical reproducibility, or visual smoothness?"
Now that you've got the basics, here's what to tackle next.
- Signals: a powerful system for keeping nodes loosely coupled.
AnimationTree: blends multiple animations and manages complex character states.- Custom resources: create reusable data sets like weapon stats and character parameters.
Learning these concepts will make your Godot projects considerably more scalable and easier to manage.