-
-
Notifications
You must be signed in to change notification settings - Fork 23.4k
Description
Godot version
3.4.2.stable.official
System information
Win10, NVIDIA GeForce GTX 960
Issue description
I am working in pixel-perfect mode (viewport). When I rotate a sprite it follows the pixel grid perfectly, just as I want. Motion is also as expected, even if I use float velocities, the character is always fixed to the pixel grid, which is exactly what I would expect.
Now this:
If I move my rotated character with integer speed, this works fine (here: 1 px per frame):
But if I move my character with float speeds (here: 1.01 px per frame), the rotation is not stable and I get jittery pixel shifts all across the sprite:
This effect seems to stem from the interaction between the float position and the float angle.
This is a version with float speed (1.01 px per frame) and int (90°) rotation, which is fine:
It seems like Godot maps the float position and angle to the pixel grid in one go, which accumulates rounding errors between the two parameters into a single step. This could lead to the fractional part of the position influencing the outcome of the rotation, which should be independent from it.
If that is the case, a solution might lie in the direction of first rounding the position before applying the rotation.
EDIT
The same seems to be happing for scaling.
I was able to see a problem with the combination of float scale and float position.
But I was also able to see the problem with int position (px/frame) and a very specific scale (1.5 or 2.5), other float scalings seem to work with int positions.
Steps to reproduce
This is the minimal example code I used (also see Godot project below). It's pretty standard. Default settings except these two:
- Display -> Window -> Size -> 320x180
- Display -> Window -> Stretch -> viewport
Change the values in the code as the comment states to get the different behaviors:
func _physics_process(delta):
var SPEED_INT = 1.0
var SPEED_FLOAT = 1.01
var ANGLE_90 = PI/2
var ANGLE_float = 1
# change these to reproduce:
# SPEED_INT / ANGLE_float --> ok
# SPEED_INT / ANGLE_90 --> ok
# SPEED_FLOAT / ANGLE_90 --> ok
# SPEED_FLOAT / ANGLE_float --> not ok
var speed = SPEED_INT
var angle = ANGLE_float
if Input.is_key_pressed(KEY_A):
self.position.x -= speed
if Input.is_key_pressed(KEY_D):
self.position.x += speed
if Input.is_key_pressed(KEY_W):
self.position.y -= speed
if Input.is_key_pressed(KEY_S):
self.position.y += speed
if Input.is_key_pressed(KEY_E):
self.rotate(angle)
if Input.is_key_pressed(KEY_Q):
self.rotate(-angle)
if Input.is_key_pressed(KEY_SPACE):
self.rotation = 0