1

I am trying to understand delta time and wrote this simple example:

import pygame, sys, time

pygame.init()
screen = pygame.display.set_mode((1280,720))
clock = pygame.time.Clock()

rect1 = pygame.Rect(0,150,100,100)
rect2 = pygame.Rect(1180,500,100,100)
speed = 300

last_time = time.time()

while True:
    dt = time.time() - last_time
    last_time = time.time()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    screen.fill('white')
    rect1.x += speed * dt
    rect2.x -= speed * dt

    pygame.draw.rect(screen,'red',rect1)
    pygame.draw.rect(screen,'green',rect2)

    pygame.display.update()
    clock.tick(60)

The problem I have with it is that the left movement is faster than the right movement. So in the code snippet the green rectangle (rect2) reaches the end of the screen noticeably faster than the red rectangle.

I also tried to use pygame.clock to get delta time:

import pygame, sys, time

pygame.init()
screen = pygame.display.set_mode((1280,720))
clock = pygame.time.Clock()

rect1 = pygame.Rect(0,150,100,100)
rect2 = pygame.Rect(1180,500,100,100)
speed = 300

while True:

    dt = clock.tick(60) / 1000

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    screen.fill('white')
    rect1.x += speed * dt
    rect2.x -= speed * dt

    pygame.draw.rect(screen,'red',rect1)
    pygame.draw.rect(screen,'green',rect2)

    pygame.display.update()

But the result remains the same.

I am really confused by this, am I doing something wrong?

Edit: Someone closed this and linked to deltatime not working at higher framerates. The framerate here is a constant 60fps.

Another_coder
  • 728
  • 1
  • 9
  • 23
  • Are the rectangles starting at equal distances from the edges of the screen? It sounds like a silly question but I can't quite tell from glancing at the positions – byxor Mar 03 '22 at 16:49
  • They do, rect 1 starts at the left side (x = 0) and rect2 has the topleft at 1180 (which is the screen width - width of the rect) – Another_coder Mar 03 '22 at 16:53
  • That's indeed interesting. If I replace `speed*dt` with a fixed number (e.g. `1`) both rectangles reach the screen edge at the exact same time. – Dschoni Mar 03 '22 at 17:27
  • oh I got an answer. The problem is that the left movement gets rounded on every frame and that causes it to slow down. – Another_coder Mar 03 '22 at 18:04

1 Answers1

1

Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.

The coordinates for Rect objects are all integers. [...]

The fraction part of the coordinates gets lost when the new position of the object is assigned to the Rect object. If this is done every frame, the position error will accumulate over time.

If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables and you have to synchronize the pygame.Rect object. round the coordinate and assign it to the position of the rectangle:

rect1 = pygame.Rect(0,150,100,100)
rect2 = pygame.Rect(1180,500,100,100)
pos1_x = rect1.x
pos2_x = rect2.x  
while True:
    # [...]

    pos1_x += speed * dt
    pos2_x -= speed * dt
    rect1.x = round(pos1_x)
    rect2.x = round(pos2_x)
 
    # [...]

See also Pygame doesn't let me use float for rect.move, but I need it

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Thank you, one more question though: Doesn't pygame automatically round the floating point numbers? This would make the round functions unnecessary. – Another_coder Mar 04 '22 at 16:46
  • @Another_coder No. By default floats are truncated (same as `int(pos1_x)`) – Rabbid76 Mar 04 '22 at 16:48