Since pygame.Rect
is supposed to represent an area on the screen, a pygame.Rect
object can only store integral data (the decimal places are lost when you assign a floating point number).
The coordinates for Rect objects are all integers. [...]
I recommend to use pygame.math.Vector2
for the problem. Store the position of the object in a pygame.math.Vector2
object:
pos = pygame.math.Vector2(start_x, start_y)
Set a direction vector depending on the keys. Scale the vector to the length of speed
with scale_to_length
. Move the object and update rect_player
:
key = pygame.key.get_pressed()
up = key[pygame.K_w] or key[pygame.K_UP]
down = key[pygame.K_s] or key[pygame.K_DOWN]
left = key[pygame.K_a] or key[pygame.K_LEFT]
right = key[pygame.K_d] or key[pygame.K_RIGHT]
move = pygame.math.Vector2(right - left, down - up)
if move.length_squared() > 0:
move.scale_to_length(speed)
pos += move
rect_player.topleft = round(pos.x), round(pos.y)
If you don't care about the floating point accuracy just move the rectangle:
key = pygame.key.get_pressed()
up = key[pygame.K_w] or key[pygame.K_UP]
down = key[pygame.K_s] or key[pygame.K_DOWN]
left = key[pygame.K_a] or key[pygame.K_LEFT]
right = key[pygame.K_d] or key[pygame.K_RIGHT]
move = pygame.math.Vector2(right - left, down - up)
if move.length_squared() > 0:
move.scale_to_length(speed)
rect_player.move_ip(round(move.x), round(move.y))
Minimal example:

import pygame
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
rect_player = pygame.Rect(0, 0, 20, 20)
rect_player.center = window.get_rect().center
speed = 5
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
up = key[pygame.K_w] or key[pygame.K_UP]
down = key[pygame.K_s] or key[pygame.K_DOWN]
left = key[pygame.K_a] or key[pygame.K_LEFT]
right = key[pygame.K_d] or key[pygame.K_RIGHT]
move = pygame.math.Vector2(right - left, down - up)
if move.length_squared() > 0:
move.scale_to_length(speed)
rect_player.move_ip(round(move.x), round(move.y))
window.fill(0)
pygame.draw.rect(window, (255, 0, 0), rect_player)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
If you derive the velocity by math.sqrt(2)
but continue to use a pygame.Rect
, it still does not lead to an accurate movement. pygame.Rect objects (rect_player
) can only store integral values (the decimal places are lost when you assign a floating point number). Therefore this works only approximately and fails completely if seed is a small value (e.g. 1). The only value for which the solution works really well is for speed=10
because 10/math.sqrt(2)
, is 7.071 (~7).