Sviluppo · Sardinia Drive
Come abbiamo costruito il motore grafico di Sardinia Drive
Come una strada descritta lungo il percorso diventa una scena in prospettiva su Canvas 2D.
Una strada in due coordinate
Nel motore dell’alpha, z è la distanza lungo la tappa e x è lo scarto laterale. Ogni curva ha un inizio, una fine e una variazione di direzione. Se t è il progresso da 0 a 1 dentro la curva, il contributo alla direzione cresce con 3t² − 2t³. La pendenza di questa funzione è zero all’ingresso e all’uscita, così la curvatura sale e scende senza scatti.
Campionare la strada restituisce la posizione del centro, la direzione e la curvatura. La guida legge la curvatura quattro unità più avanti, mentre la camera usa la tangente alla posizione del giocatore. La stessa curva del Lago Cuga entra così sia nel disegno sia nella forza laterale che senti al volante.
Da una distanza ai pixel
Il renderer misura lo scarto del punto osservato rispetto alla tangente della strada sotto il giocatore. Nel calcolo, baseHeading è la pendenza laterale locale, moltiplicata per la distanza in avanti. Sottrae anche l’87% dello scarto laterale del veicolo, così la camera lo segue parzialmente quando sterza. Poi converte gli scarti in pixel moltiplicandoli per la focale divisa per la profondità.
depth = roadPointZ - playerZ
scale = focalLength / depth
offset = roadCenter - baseCenter - baseHeading * depth
screenX = canvasWidth / 2 + (offset - 0.87 * playerX) * scale
screenY = horizonY + cameraHeight * scale
Prendiamo un buffer Canvas da 900 × 600 pixel durante la gara. L’orizzonte è a y = 243, la focale è 396 e l’altezza della camera è 2,05 unità. Per una sezione larga 7,8 unità, i conti danno questi risultati.
| Profondità | Larghezza in pixel | Riga sul canvas |
|---|---|---|
| 15 unità | 206 | 297 |
| 30 unità | 103 | 270 |
Raddoppiando la distanza, si dimezzano sia la larghezza sia lo scarto verticale dall’orizzonte. L’aumento di scala in primo piano è uno dei segnali visivi della velocità.
Una strada fatta di quadrilateri
Il renderer percorre fino a 225 unità davanti al giocatore, in passi da 3. Proietta le estremità lontana e vicina di ogni striscia e unisce i quattro punti. Lo stesso passaggio disegna asfalto, bordi e tratteggio con scarti laterali diversi. Le strisce lontane vengono dipinte per prime e quella più vicina si ferma a 1,35 unità dalla camera, dove la divisione per la profondità amplificherebbe troppo la scala.
Al Lago Cuga la riva usa lo stesso principio. La larghezza è massima al centro del lago e scende secondo un profilo parabolico fino a zero a 170 unità dal centro. Il renderer calcola una larghezza per ciascuna estremità della striscia. Anche il margine della corsia chiusa ai lavori parte da uno scarto laterale e segue la curva dell’asfalto.
Come si sovrappongono gli sprite
Dopo la strada, il motore raccoglie gli oggetti a bordo strada, il traffico e il veicolo del giocatore in una lista ordinata per z, dal più lontano al più vicino. Un pullman più vicino può coprire un ulivo disegnato prima. L’ordinamento usa un punto di ancoraggio per sprite. Con sagome grandi che si incrociano, la sovrapposizione è quindi un’approssimazione.
Per il giocatore il motore calcola a quale profondità l’asse posteriore cadrebbe all’82% dell’altezza dello schermo. Inserisce l’asse nella stessa lista e applica lo stesso scarto di profondità al traffico. I veicoli del giocatore usano tre pose da 320 × 320 pixel in un atlante WebP. Sterzo e derapata selezionano la posa, poi il renderer aggiunge rotazione e ombra.
Orizzonte, inquadratura e costo in pixel
Il fondale di Capo Caccia è tagliato alla linea dell’acqua. Il renderer allinea le due parti allo stesso orizzonte della strada e fa scorrere i riflessi con velocità diverse. All’arrivo in verticale riduce la focale fino al 77% del valore di gara, allargando l’inquadratura. Cronometro e avanzamento sono elementi HTML sopra il canvas e restano fermi.
Il buffer del canvas usa il rapporto di pixel del dispositivo fino a un massimo di 1,5. Su un telefono da 3× il buffer contiene circa un quarto dei pixel che avrebbe alla risoluzione nativa. Il browser ridimensiona il risultato alla superficie visibile. È il compromesso scelto per contenere il numero di pixel da ridisegnare.