Platformer 2D: perché rendere la fisica dipendente dal framerate?


12

"Super Meat Boy" è un platform difficile che è recentemente uscito per PC, che richiede un controllo eccezionale e un salto perfetto per i pixel. Il codice fisico nel gioco dipende dal framerate, che è bloccato a 60fps; questo significa che se il tuo computer non è in grado di eseguire il gioco alla massima velocità, la fisica diventerà pazza, causando (tra le altre cose) il tuo personaggio a correre più lentamente e cadere nel terreno. Inoltre, se vsync è disattivato, il gioco funziona estremamente velocemente.

Quelli che hanno esperienza con la programmazione di giochi 2D potrebbero spiegare perché il gioco è stato codificato in questo modo? Un circuito fisico che funziona a un ritmo costante non sarebbe una soluzione migliore? (In realtà, penso che un ciclo di fisica sia usato per parti del gioco, poiché alcune entità continuano a muoversi normalmente indipendentemente dal framerate. Il tuo personaggio, invece, corre esattamente [fps / 60] il più velocemente.)

Ciò che mi preoccupa di questa implementazione è la perdita di astrazione tra il motore di gioco e il rendering grafico, che dipende da elementi specifici del sistema come il monitor, la scheda grafica e la CPU. Se, per qualsiasi motivo, il tuo computer non è in grado di gestire vsync o non può eseguire il gioco esattamente a 60 fps, si romperà in modo spettacolare. Perché la fase di rendering dovrebbe in qualche modo influenzare i calcoli della fisica? (La maggior parte dei giochi oggigiorno rallenterebbe il gioco o salterebbe i frame.) D'altra parte, capisco che i platform della vecchia scuola su NES e SNES dipendevano da un framerate fisso per gran parte del loro controllo e fisica. Perché è questo, e sarebbe possibile creare un formulatore in tal senso senza avere la dipendenza framerate? Vi è necessariamente una perdita di precisione se si separa il rendering grafico dal resto del motore?

Grazie e scusa se la domanda era confusa.


Tangenziale alla tua domanda. Ecco un ottimo articolo che copre esattamente i problemi che stai descrivendo e il modo "giusto" per gestire i timestep e i frame rate. gafferongames.com/game-physics/fix-your-timestep
num1

In realtà mi ha davvero sorpreso che lo farebbero in questo modo. Suppongo che sia dovuto al fatto che è stato creato principalmente per console, su cui si può fare affidamento sulla frequenza dei fotogrammi. ! deludente
Iain,

Risposte:


7

Perché?

Una manciata di ragioni, fai la tua scelta: non sapevano niente di meglio. È più veloce e più facile da implementare. Erano concentrati più sul gameplay e meno sui casi limite che nella maggior parte dei casi potrebbero non emergere.

Hai fatto un ottimo lavoro nel spiegare perché no. Sono sicuro che hai notato che ci sono molti argomenti che trattano l'argomento . Non sono sicuro che troverai una risposta soddisfacente oltre a quelle che ho elencato.


"Non sapevano niente di meglio" descrive perché ho adottato questo approccio con "Jack is a Fool". Ma - ho fatto molto affidamento sul chiamare il dt dall'ultimo fotogramma con tutta la mia logica. Ma - con coordinate in virgola mobile, può portare ad alcuni bug strani, difficili da replicare
lochok

4

SMB era originariamente un gioco per console in cui si può presumere che sia in grado di funzionare a 60 fps su tutti gli Xbox 360 (beh, forse 50 per alcuni giocatori PAL). Supponendo che un timestep fisso semplifichi un po 'il codice.

Mentre è facile scalare molte cose in base a un timestep variabile - 'pos + = velocity * timestep', diventa abbastanza difficile farlo correttamente quando si hanno a che fare con accelerazioni, tassi di variazione dell'accelerazione e così via.

Il disaccoppiamento del gameplay e del rendering è una buona soluzione in teoria , ma implementarla bene (con una buona interpolazione) è piuttosto complicata e le cose possono facilmente diventare confuse. È abbastanza raro che questa tecnica venga utilizzata nei giochi reali (anche se alcuni grandi giochi lo fanno, in particolare i giochi RTS, ma più per la sincronizzazione dei giochi di rete).

Quando si progetta anche una risoluzione dello schermo fissa e un framerate fisso, c'è un'altra cosa che puoi fare per rendere lo scorrimento ancora più fluido. Puoi assicurarti che il gioco scorra per un numero intero di pixel per fotogramma, evitando qualsiasi "oscillazione subpixel" che potresti ottenere facendo scorrere un numero frazionario di pixel per fotogramma.


1

La soluzione ovvia è avere 2 loop in esecuzione in parallelo: il rendering ogni 1/60 di secondo e il loop di gioco ogni 1/60 di secondo.

Ma con la mia esperienza in Flash (AS3, di cui sono sicuro che sia stato creato Super Meat Boy), lo scheduler non è sempre molto preciso. La precisione dipende anche fortemente dall'ambiente. Nel flash player autonomo, potrebbe avere una risoluzione inferiore al millisecondo. Ma quando viene eseguito in alcuni browser Web, la precisione diventa quella del frame rate.

Quindi il modo più vicino per disaccoppiare il rendering e i circuiti logici di gioco è avere tutti i movimenti basati sul tempo (ed eseguire ciascun fotogramma in base al tempo trascorso dall'ultimo fotogramma). Ciò può introdurre una matematica più complicata (come avere la gravità da applicare continuamente, piuttosto che aggiungere alla velocità di un oggetto a intervalli prestabiliti). Poiché il gioco potrebbe ritardare per un secondo e quindi il tuo giocatore si sposterà di 200 pixel in un solo passaggio, il rilevamento e la risposta delle collisioni possono diventare ancora più complicati. Se il programmatore stava eseguendo il rilevamento delle collisioni basato su frame (controllando una collisione ogni volta), dovrebbe passare anche al rilevamento delle collisioni basato sul tempo. E se volessero che sembrasse naturale, avrebbero dovuto usare il metodo di gravità sopra descritto, che fa sì che il movimento dell'oggetto sia una curva (al contrario di una linea),


2
Il Meat Boy originale era un gioco Flash. Super Meat Boy è un gioco in C ++.
Archagon,

0

Non credo sia troppo chiedere ai giochi per PC 2D di giocare più a 60fps. Anche la maggior parte dei giochi 2D sono accelerati dall'hardware, quindi personalmente non mi preoccuperei del requisito fps.

La vera domanda è perché non dovresti usare un pixel based, i giochi sono pieni di cheat e scorciatoie.

Se stai realizzando un gioco basato sulla fisica (forse lanciare uccelli?) La risposta è ovvia, ma un clone di super mario? il movimento basato sul tempo potrebbe essere un po 'troppo.


Non è difficile riprodurli a 60fps, ma i display con frequenze di aggiornamento native di 50Hz, 70-85Hz e 120Hz sono ancora facilmente reperibili.

0

Per evitare strani comportamenti nella fisica 2D che stanno usando?

Onestamente posso solo indovinare. Proverò una spiegazione:

Al centro del gioco c'è il loop principale del gioco. Che sostanzialmente assomiglia a questo:

while(gameRunning)
{
  updateGame(timestep);
  renderGame(timestep);
}

updateGame aggiorna il gameState: controlla l'input del giocatore, applica l'input del giocatore al mondo di gioco ed esegue la simulazione fisica ecc.

renderGame disegna e anima il gioco.

Questo accoppia l'aggiornamento di fisica al rendering. Se si desidera disaccoppiarlo, è necessario utilizzare i thread e sincronizzare correttamente ogni accesso ai dati del rendering e il thread gameUpdate con i dati condivisi, ad esempio la posizione del giocatore. Questo può essere fatto.

Un altro problema potrebbe essere che la simulazione fisica richiede un timestep costante per funzionare in modo stabile. Questo dipende da come supermeatboy calcola il movimento (di nuovo possiamo solo indovinare come l'hanno fatto;)).

Un approccio ingenuo sarebbe (che sto usando nel mio gioco * sigh *):

position=position+speed*timestep;
speed=speed+acceleration*timestep;

Questo si chiama Euler Integration ed è generalmente considerato una cattiva idea. Se la data / ora è costante, si verificano errori di calcolo che rendono la simulazione meno stabile. L'oggetto potrebbe muoversi a velocità eccessive o non tutte o volare attraverso i muri fuori dallo schermo. Anche se il timestep è costante, l'integrazione di Euler causa piccoli errori di calcolo. Meglio usare un altro metodo di integrazione come RK4 o usare un motore fisico.

A parte ciò, possono verificarsi problemi nel rilevamento delle collisioni se il timestep diventa troppo grande. Poiché le collisioni non vengono verificate tra due GameUpdate, gli oggetti potrebbero passare attraverso ostacoli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.