Menu
CoddyTech

Une animation fluide à toute fréquence d’images

Fait partie de la section Son et sensations de jeu du Journey Pygame de Coddy. Leçon 19 sur 23.

x += (target_x - x) * 0.1 parcourt un dixième du chemin à chaque image. À 60 images par seconde, cela fait 60 étapes par seconde ; sur un ordinateur lent qui n’en affiche que 30, il n’y en a que 30, et le cercle met deux fois plus de temps à arriver. Appuie sur F pour le voir : le jeu tourne à 30 images par seconde et tout ralentit.

La solution consiste à mesurer le temps. clock.tick() renvoie le nombre de millisecondes écoulées depuis la dernière image. Divisé par 1000, cela donne dt, la durée de l’image en secondes : environ 0.017 à 60 images par seconde, 0.033 à 30.

dt = 1 / 60          # avant la boucle
...
step = min(1, 6 * dt)
x += (target_x - x) * step
...
dt = clock.tick(fps) / 1000

Une image plus longue entraîne un déplacement plus important, de sorte que le cercle parcourt la même distance dans le même temps, quel que soit le nombre d’images par seconde. Le 6 définit la vitesse : à 60 images par seconde, 6 * dt vaut environ 0.1, soit le même dixième qu’avant. min(1, ...) empêche une image très longue de faire dépasser la cible.

Il en va de même pour un déplacement simple : player_x += 240 * dt correspond à 240 pixels par seconde, quel que soit le nombre d’images par seconde. La plupart des petits jeux fixent leur fréquence avec tick(60) et n’ont jamais besoin de cela ; utilise dt lorsque la fréquence peut varier.

challenge icon

Défi

Moyen

La touche F fait passer le jeu de 60 à 30 images par seconde. Fais en sorte que l’interpolation prenne le même temps dans les deux cas :

  1. Définis dt = 1 / 60 avant la boucle.
  2. À la fin de la boucle, définis dt = clock.tick(fps) / 1000.
  3. Déplace-toi avec step = min(1, 6 * dt) au lieu de 0.1 : x += (target_x - x) * step, et fais de même pour y.

Essayez vous-même

import pygame

pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Any Frame Rate")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 28)

x, y = 240, 180
target_x, target_y = 240, 180
fps = 60

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            target_x, target_y = event.pos
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
            fps = 30 if fps == 60 else 60

    x += (target_x - x) * 0.1
    y += (target_y - y) * 0.1

    screen.fill((30, 30, 46))
    pygame.draw.circle(screen, (80, 200, 220), (x, y), 12)
    label = font.render(f"{fps} FPS (F to change)", True, (240, 240, 240))
    screen.blit(label, (10, 10))
    pygame.display.flip()
    clock.tick(fps)

pygame.quit()
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Son et sensations de jeu

Entraînez-vous par vous-même : Playground Pygame