Description
Environment:
- Operating system: Windows 11
- Python version: 3.11.4
- SDL version: 2.26.5
- PyGame version: 2.3.1
Current behavior:
When FRects are positioned off screen using negative values (i.e. off the top of the screen (-y), or left of the screen(-x)) they are 1 pixel out from where they should be. I think this is because pygame-ce is either dealing with floats in the FRect as ints, or is calculating floor for positive values and ceil for negative values (I assume it's int conversion but might be wrong).
Expected behavior:
FRects should use the same method of calculation for both negative and positive values, I would expect calculating floor values would be the correct way.
Steps to reproduce:
- create a program where a surface uses FRect for positioning
- animate/move the surface off screen (either the top or the left) in small amounts i.e. not integers
- observe the positioning which stutters or pauses while it transitions from positive to negative values (caused by values ranging from 0.9 to -0.9 recurring all being truncated/converted to 0)
Test code
You should be able to notice the circle appears to pause when it reaches the top of the screen, and this is because there it spends twice as long at position 0 due to the int conversion for values between 0.9999 and -0.9999.
import time
import pygame
pygame.init()
timer = pygame.time.Clock()
WIDTH = 800
HEIGHT = 600
screen = pygame.display.set_mode((300, 200), pygame.SCALED)
main_font = pygame.font.SysFont(None, 24)
circle_surf = pygame.Surface((102, 102), pygame.SRCALPHA)
pygame.draw.circle(circle_surf, "red", (51, 51), 51, 1)
circle_surf_frect = pygame.FRect(circle_surf.get_rect(topleft=(9, 9)))
frame_start_time = time.time()
running = True
while running:
delta_time = time.time() - frame_start_time
frame_start_time = time.time()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
frect_y_render = main_font.render(
f"FRect.x: {round(circle_surf_frect.y, 4)}", False, "yellow"
)
y_coord_render = main_font.render(
f"Pixel x: {int(circle_surf_frect.y)}", False, "yellow"
)
screen.fill("midnightblue")
screen.blit(circle_surf, circle_surf_frect)
screen.blit(frect_y_render, (120, 20))
screen.blit(y_coord_render, (120, 40))
circle_surf_frect.y -= 2 * delta_time
pygame.display.flip()
timer.tick(60)
Other information
In the rect_test.py
file I think the test_clipline_floats
test would fail if a test was performed that included negative x and y values as it uses floor to check the values.