Godot Version
v4.7.2.stable.official [ed1daf0bf]
Hi everyone,
First of all, I’m sorry in advance if this post is a mess or if my whole concept is misguided — I’ve been stuck on this for a while and I’m genuinely not sure anymore whether I even want the right thing or whether my approach can work at all, so please bear with me.
The concept:
I’m trying to make a game that plays like a 2D game but takes place in a 3D world: a top-down, slightly side-angled camera, pixel-art sprites standing in a real 3D scene (so, 2.5D). In Godot terms: a CharacterBody3D player with a collision shape and a sprite as a child, plus a Camera3D on a rig looking down at the arena from a slight angle.
The problem:
As you can see in the attached video, the character sprite jitters / stutters constantly while walking. The movement logic itself works fine, but the sprite visibly shakes instead of moving smoothly pixel-by-pixel, which completely breaks the pixel-art look.
My setup and the rules I followed:
- Godot 4.7.2 stable
- Pixel-art scale: 16 pixels = 1 meter in the 3D world
- Texture filtering set to Nearest everywhere (project default + import settings), mipmaps off
- A bunch of other “pixel-perfect” tricks I found (snapping on/off, integer zoom, etc.) — honestly, I tried so many contradictory things, including the exact opposites of each other, that I lost track of what is currently “correct”. Maybe I should have done everything the other way around? I have no idea anymore.
Player movement code (_physics_process + move_and_slide()):
class_name PlayerController
extends CharacterBody3D
@export var move_speed: float = 2.0
func _physics_process(delta: float) → void:
var input_dir := Input.get_vector(“move_left”, “move_right”, “move_up”, “move_down”)
var move_direction := Vector3(input_dir.x, 0, input_dir.y).normalized()
if move_direction:
velocity.x = move_direction.x * move_speed
velocity.z = move_direction.z * move_speed
else:
velocity.x = move_toward(velocity.x, 0, move_speed)
velocity.z = move_toward(velocity.z, 0, move_speed)
move_and_slide()
My questions:
- What typically causes this kind of jitter in a 2.5D pixel-art-in-3D setup — sub-pixel camera movement, physics-vs-render desync, or a wrong pixels-per-meter scale?
- Is my approach fundamentally wrong? Maybe I should do the opposite: render the 3D scene into a low-resolution viewport and upscale it an integer number of times, instead of trying to keep everything pixel-snapped in a full-res 3D view?
- What is the recommended way to get a crisp, jitter-free “2D look in a 3D world”?
Video:
Sorry again if I’m mixing up concepts or asking something obvious — I’m ready to redo the whole rendering approach if that’s what it takes. Any pointers would be hugely appreciated.
Thanks!