Fluidità a qualsiasi frequenza di fotogrammi
Fa parte della sezione Suoni e sensazioni di gioco del percorso Pygame di Coddy. Lezione 19 di 23.
x += (target_x - x) * 0.1 percorre un decimo della distanza per fotogramma. A 60 fotogrammi al secondo sono 60 passaggi al secondo; su un computer lento che riesce a gestirne solo 30, sono 30 passaggi e il cerchio impiega il doppio del tempo per arrivare. Premi F per vederlo: il gioco gira a 30 e tutto rallenta.
La soluzione è misurare il tempo. clock.tick() restituisce i millisecondi trascorsi dall'ultimo fotogramma. Dividendo per 1000 si ottiene dt, la durata del fotogramma in secondi: circa 0.017 a 60 fotogrammi al secondo, 0.033 a 30.
dt = 1 / 60 # prima del ciclo
...
step = min(1, 6 * dt)
x += (target_x - x) * step
...
dt = clock.tick(fps) / 1000Un fotogramma più lungo comporta un passo più grande, quindi il cerchio percorre la stessa distanza nello stesso tempo a qualsiasi frequenza di fotogrammi. Il 6 imposta la velocità: a 60 fotogrammi al secondo, 6 * dt è circa 0.1, lo stesso decimo di prima. min(1, ...) impedisce a un fotogramma molto lungo di far superare il bersaglio al passo.
Lo stesso vale per il movimento semplice: player_x += 240 * dt equivale a 240 pixel al secondo, qualunque sia la frequenza di fotogrammi. La maggior parte dei giochi piccoli fissa la frequenza con tick(60) e non ha mai bisogno di questo; usa dt quando la frequenza può cambiare.
Sfida
MedioF alterna il gioco tra 60 e 30 fotogrammi al secondo. Fai in modo che l’interpolazione richieda lo stesso tempo a entrambi:
- Imposta
dt = 1 / 60prima del ciclo. - Alla fine del ciclo, imposta
dt = clock.tick(fps) / 1000. - Sposta con
step = min(1, 6 * dt)invece di 0.1:x += (target_x - x) * step, e lo stesso pery.
Provalo tu
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()
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Suoni e sensazioni di gioco
1Effetti sonori
Caricare un suonoSuono al verificarsi di un eventoVolume del suonoSuoni e tasti tenuti premuti4Scuotimento dello schermo e flash all’impatto
Scuotimento dello schermoFlash all’impattoPausa all’impattoMantienilo discreto5Movimento fluido
Muoversi verso un obiettivoUna telecamera fluidaEffetto pop alla raccoltaFluidità a qualsiasi frequenza di fotogrammiEsercitati da solo: Playground Pygame