Pixel Art Jittering

Hi!

I’ve tried a lot to achieve a pixel-perfect style in my game, but one annoying issue I can’t solve is jittering when I use Snap 2D Transforms to Pixel and Snap 2D Vertices to Pixel.

I use constant speed multiplied by normalized Input.get_vector, CharacterBody2D.velocity and move_and_slide().
I’ve also experimented a lot with the Camera settings, but it doesn’t resolve the problem. Currently, my Camera settings include 4x Zoom, Limit, Horizontal and Vertical Drag. I call camera.reset_smoothing() and camera.force_update_scroll() in the _ready function. Physic or Idle process callback doesn’t make any differences.

Adjusting the Window settings doesn’t solve the problem. I experience this issue in all stretch modes. My current approach is to keep Stretch – Mode – disabled and only adjust the camera zoom.

The sprites are 1:1 pixel-perfect. v4.2.2.stable.official

Video preview:

Is this an issue with physics interpolation, perhaps? I have a 144hz monitor and always get physics jitter with a 60hz physics tick rate without using the legendary smoothing addon:

2D physics interpolation was recently added to 4.3, but 4.2.2 doesn’t feature built-in physics interpolation. (3D physics interpolation should be in 4.4)

Also, the tooltip for those two Snap 2D settings (in 4.3 at least) say not to use them together as having both setting enabled could make things less smooth. Maybe try only using one or the other and see if that changes anything.

1 Like

To confirm what Namdaets said. You should have less issues in 4.3, and you should only use Snap 2D Transforms to Pixel.

Further if you’re going for a pixel perfect game, you should have the stretch mode set to Viewport and not use zoom.

1 Like

@markdibarry @Namdaets thanks!

I updated Godot to 4.3 and left only Snap 2D Transforms to Pixel enabled. I also changed the stretch mode to Viewport and turned off all zoom features in the camera.

Still have problems with jittering :slightly_frowning_face:
Maybe I’ll try add-on later…

I don’t see any jittering issues in your video, but what you’re probably confusing for jitter is the classic diagonal stepping problem, which is unfortunately the natural behavior of snapping pixels when your actual positions are floats underneath.

Here’s a video showing what it looks like when you snap the item’s rendering while the actual position moves at a 45 degree angle. The lines represent the actual float position of the boxes. The left starts exactly at a whole number and moves to another whole number. The middle is offset by 0.25, and the right is offset by 0.5.

As a matter of fact, there are a lot of new games that have come out recently that still suffer from this problem (I noticed it recently in Eiyuden Chronicle). It usually requires custom code to either actually snap your positions when moving diagonally, or logic for how you want your game to interpret the intent of your movement.

1 Like

@markdibarry I recorded another example when you can see it without diagonal moving

Ah! I see what you mean now. That looks like your camera is out of sync with your character, updating one frame later. There’s a lot of different things that could cause that, but I haven’t seen it in awhile. Would you be able to share your project or a minimal reproduction? I could tell you exactly the cause and how to fix it, if so.

@markdibarry of course, it’s kinda tiny right now, but with some unused stuff.

Ah, I see the problem. Two things.

  1. (unrelated) Set your scale mode to integer, so when you change your screen size the pixels are even.
  2. The camera is attached to your character. Your character’s sprite rendering snaps to the nearest rounded position, but the character still has the float position, so your camera has that float position too.

The easy fix would be to just add a rounding to your camera after you update the movement.

func _physics_process(delta):
	if PlayerManagerAutoload.controllable:
		player_movement()
	camera.global_position = global_position.round()

I think this should be a feature that’s added in though at some point. I’ll see if I can make a PR for 4.4.

4 Likes

@markdibarry you are hero!

Now I don’t have problems with straight movement.
(Still have with diagonal, but it’s different problem as you noticed)

1 Like

I somehow solved it in my project.
Here are my settings(Godot 4.2.2.stable):

Project Settings

→ Display → Window
Viewport Width = 1920
Viewport Height = 1080
Mode = Exclusive Fullscreen
Aspect = Expand
Scale = 1.5

→ Rendering -->2D
Snap 2D Transforms to Pixel = ON
Snap 2D Vertices to Pixel = ON

Player Script

after move_and_slide()

global_position = round(global_position/ 2) * 2

Scene Settings

Scale all scenes(Player, TileMap, etc.) x 2.

I can’t even explain why this works…

You can use my texture for testing.


Don’t forget to scale.
Hope it helped :v:

1 Like

Isn’t enough to just setting the Scale Mode to “integer” in the Project Settings (under Display → Window)?

@triplefff Thanks! But 2x scale is not my way, I want to leave it 1x, cause I don’t want any half-pixel statements of player etc.
@Stefh Not enough, sadly.

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