Do not try to control the object with a loop inside the application loop. Use the application loop.
You have to handle the events in the application loop. See pygame.event.get()
respectively pygame.event.pump()
:
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
Use pygame.time.Clock
to control the frames per second and thus the game speed.
The method tick()
of a pygame.time.Clock
object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick()
:
This method should be called once per frame.
pygame.time.Clock.tick
returns the number of milliseconds since the last call. When you call it in the application loop, this is the number of milliseconds that have passed since the last frame. Multiply the objects speed by the elapsed time per frame to get constant movement regardless of FPS.
Define the distance in pixels that the player should move per second (move_per_second
). Then compute the distance per frame in the application loop.
pygame.Rect.move
doesn't change the Rect
object itself, but it returns an new Rect
object. This means, that
rect.move(dx, 0)
doesn't change anything. You've to assign the rectangle which is returned by .move
to "itself":
rect = rect.move(dx, 0)
Alternatively you can use pygame.Rect.move_ip
rect.move_ip(dx, 0)
Minimal example:
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 250, 20, 20)
bot_vel = 500 # 500 pixel / second
run = True
while run:
dt = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
dx = bot_vel * dt / 1000
rect.move_ip(dx, 0)
if rect.x > screen.get_width():
rect.x = 0
screen.fill((0,0,0))
pygame.draw.rect(screen, (255,255,255), rect)
pygame.display.flip()
pygame.quit()
exit()