Skip to content

FRect - incorrect positioning for negative values #2409

Open
@rethanon

Description

@rethanon

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:

  1. create a program where a surface uses FRect for positioning
  2. animate/move the surface off screen (either the top or the left) in small amounts i.e. not integers
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Surfacepygame.SurfacebugNot working as intended

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions