Ваша основная проблема заключается в том, что вы проверяете наличие нажатых клавиш в цикле событий:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# only executed if there's an event returned by pygame.event.get()
# and possible executed multiple times per frame
key = pygame.key.get_pressed()
if key[K_UP]:
...
Следовательно, ваш код, выполняющий движение (if key[K_UP]: ...
), выполняется только тогда, когда в данный момент происходит событие вочередь.
Просто переместите этот код за пределы цикла обработчика событий:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# always executed every frame
key = pygame.key.get_pressed()
if key[K_UP]:
...
ИМХО лучший способ справиться с вашим движением - это использовать векторы, поскольку они упрощаютобеспечить постоянную скорость движения и значительно меньше кода.
Вот простой пример:
import pygame
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
dt = 0
movement = {
pygame.K_UP: ( 0, -1),
pygame.K_DOWN: ( 0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: ( 1, 0)
}
pos = pygame.Vector2((100, 100))
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
pressed = pygame.key.get_pressed()
# calculate the movement vector
move = pygame.Vector2()
for dir in (movement[key] for key in movement if pressed[key]):
move += dir
if move.length() > 0: move.normalize_ip()
# ensure we have a constant speed
pos += move * dt/5
screen.fill(pygame.Color('grey'))
pygame.draw.circle(screen, pygame.Color('dodgerblue'), [int(x) for x in pos], 20, 0)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()