La stessa navicella su ogni schermo

Una classifica giornaliera è equa solo se volare lo stesso tratto di grotta è ugualmente difficile su un vecchio telefono piccolo, un tablet a 144 Hz e un browser desktop. Ecco cosa ci è voluto, e cosa non sono riuscito a rendere uguale.

Devlog · 20 settembre 2026 · tutti gli articoli

Il post sulla grotta giornaliera riguarda il rendere il mondo identico per ogni giocatore. Questo riguarda l'altra metà dell'equità: far comportare la navicella in modo identico. Ci sono due modi distinti in cui un dispositivo può cambiare come si gioca, e servono due correzioni distinte. Uno è la frequenza con cui lo schermo si aggiorna. L'altro è quanto è grande lo schermo.

Problema uno: il frame rate

La navicella ha una posizione e una velocità. Ad ogni frame, gravità o spinta cambiano la velocità, e la velocità cambia la posizione. Il modo ovvio per scriverlo è:

vy += accel * dt;     // update velocity
py += vy * dt;        // then move by the NEW velocity

Sembra innocuo, ma è sottilmente sbagliato. La seconda riga finge che la navicella abbia già trascorso l'intero frame viaggiando alla sua velocità di fine frame. Se la navicella sta accelerando, questo sovrastima di metà di accel × dt² ad ogni singolo frame. Il problema è che dt, la durata del frame, è diversa su ogni dispositivo, quindi anche la sovrastima è diversa, e una navicella percorreva un percorso leggermente diverso ad ogni frame rate.

L'ho misurato con una spinta mantenuta per mezzo secondo. La risposta esatta è 225 pixel. Il vecchio integratore dava 228 a 144 Hz, 232 a 60 Hz e 240 a 30 Hz. Tre dispositivi, tre distanze diverse, dallo stesso input.

La correzione è la regola del trapezio, che usa la media della velocità prima e dopo il frame:

const vyPrev = vy;
vy += accel * dt;
py += (vyPrev + vy) * 0.5 * dt;   // average speed over the frame

Per un'accelerazione costante è esatta, qualunque sia la durata del frame. Rigiocare una sequenza di input identica ora dà una dispersione di 0,000 pixel tra 12 e 144 Hz. Prima era 4,1 pixel. Un test verifica entrambe le metà: che il nuovo integratore concordi su tutti i frame rate e che il vecchio divergesse davvero, così se qualcuno lo ripristina, il test fallisce invece che la classifica derivi silenziosamente.

Due avvertenze oneste

Non ha colmato il divario di punteggio tra frame rate. Me lo aspettavo. Un pilota simulato segnava ancora circa un terzo in più a 144 Hz rispetto a 60 Hz dopo il cambiamento. Quel divario non è fisica. È risoluzione dell'input: un pollice può passare da premuto a rilasciato solo al confine di un frame, quindi uno schermo più veloce dà davvero un controllo più fine. Nessun integratore può risolverlo, e un bot che inverte il suo input ad ogni frame lo esagera rispetto a un umano. La metà fisica ora è esatta, e il resto è una proprietà dell'hardware.

È un nerf molto leggero a 60 Hz. Una salita di mezzo secondo ora copre 225 pixel invece di 232. Ho lasciato questo non compensato. Se un test su dispositivo reale trovasse mai la navicella lenta, la leva è la costante di spinta, circa il 3% in più ripristinerebbe la vecchia manovra di mezzo secondo. Questo è un buon momento per dire che la spinta è già stata cambiata due volte per feedback dei giocatori, e quella storia è il motivo per cui sono cauto nel toccarla.

Problema due: l'altezza dello schermo

La gravità in pixel al secondo quadrato significa cose molto diverse su un telefono alto 375 punti e un tablet alto 520 punti. Se le costanti fossero le stesse, la stessa salita attraverserebbe una frazione molto più piccola dello schermo sul tablet, e il gioco sembrerebbe più pesante.

Quindi le costanti sono definite rispetto a un'altezza di riferimento di 440 punti, l'altezza in orizzontale del più grande iPhone, dove la sensazione del gioco è stata calibrata e testata. Su qualsiasi altro schermo, gravità, spinta e velocità terminale vengono tutte moltiplicate per H / 440. Poiché anche il semi-vuoto del corridoio si scala con l'altezza, ogni traiettoria è geometricamente simile a quella di riferimento: la stessa frazione del corridoio attraversata al secondo, lo stesso tempo per andare da un muro all'altro, la stessa reattività percepita. Uno schermo più grande ottiene un'accelerazione più ripida in pixel, e uno più piccolo una più dolce, di proposito.

Questo porta con sé una regola per tutto il codice futuro: tutto ciò che ragiona sul movimento verticale deve essere basato su rapporti. Una frazione della velocità terminale, una frazione dell'altezza. Mai una costante grezza in pixel al secondo confrontata con la velocità della navicella, perché quel numero è corretto solo su un dispositivo. Se un valore letterale è inevitabile, viene moltiplicato per la stessa scala.

La versione web segue la stessa regola. La build del browser limita il suo canvas a 956 per 440, la stessa impronta di quel telefono di riferimento, quindi il gioco in un browser ne è una copia pixel e fisica esatta. Una precedente build web aveva il proprio moltiplicatore di sensazione separato, che esisteva solo per contrastare la mollezza causata da un limite diverso, ed è stato eliminato una volta che il limite è stato allineato.

Problema tre: la larghezza dello schermo

L'altezza è l'asse verticale. La larghezza è quello orizzontale, ed è più sottile. Gli ostacoli sono distanziati a distanze fisse nel mondo. La grotta scorre a una velocità che include un fattore per la larghezza dello schermo. Quindi su uno schermo più largo gli stessi ostacoli scorrono più velocemente in termini di schermo, e il tempo che hai per reagire a ciascuno diminuisce in proporzione alla larghezza.

Questa era una vera falla. Un grande tablet Android largo circa 1280 punti affrontava la grotta condivisa circa 1,75 volte più velocemente di un telefono piccolo. Quindi la larghezza è limitata a 956 punti su ogni piattaforma, la larghezza del più largo iPhone in orizzontale. Un dispositivo più largo di così ottiene barre nere a sinistra e a destra. È un no-op sugli iPhone e limita solo grandi dispositivi Android e browser desktop.

Il limite ha un residuo che non ho corretto. Il raggio di collisione del giocatore si scala con la larghezza mentre il corridoio si scala con l'altezza, quindi su un tablet più quadrato la navicella è un po' più piccola rispetto al varco rispetto a un telefono, circa il 20% più indulgente. Correggerlo significa cambiare la hitbox, il che è un cambiamento di sensazione che richiede un proprio playtest, e sbaglia nella direzione indulgente, quindi può aspettare.

Testare l'equità invece di affermarla

Niente di tutto questo è visibile giocando. Non puoi sentire pochi pixel di deriva, e nessuno gioca la stessa grotta su sei dispositivi contemporaneamente. Quindi ogni affermazione ha un test che la riproduce: il test fisico integra un input fisso a frame rate da 12 a 144 Hz, e un test della grotta riproduce i veri generatori su sei dimensioni di dispositivo e confronta il risultato byte per byte. Una proprietà di equità che non testi si è già, nella mia esperienza, silenziosamente rotta.

In breve, TUNL è equo tra schermi in tre modi distinti (frame rate, altezza e larghezza), ognuno con una causa diversa, una correzione diversa e un residuo diverso. Puoi vedere il risultato da solo, su qualsiasi dispositivo tu abbia, nella grotta di oggi.

Gioca la grotta di oggi