Case study - Ridimensionamento automatico dei giochi HTML5

Derek Detweiler
Derek Detweiler

Introduzione

Nell'estate del 2010 abbiamo creato Sand Trap, un gioco a cui abbiamo partecipato a un concorso sui giochi HTML5 per cellulari. Tuttavia, la maggior parte dei telefoni cellulari mostrava solo una parte del gioco o rendeva il gioco troppo piccolo, rendendolo completamente ingiocabile. Per questo motivo, ci siamo impegnati per adattare il gioco in modo fluido a qualsiasi risoluzione. Dopo aver riprogrammato e utilizzato le idee descritte in questo articolo, avevamo un gioco che si è adattato a qualsiasi browser moderno, sia che venisse eseguito su computer o su un dispositivo mobile.

Screenshot della visualizzazione a schermo intero
screenshot di dimensioni più piccole nella finestra del browser

Questo approccio ha funzionato bene per Sand Trap, quindi abbiamo utilizzato lo stesso metodo per il nostro ultimo gioco, Thwack!. Il gioco regola automaticamente le risoluzioni dello schermo per adattarsi sia a schermo intero sia a finestre di dimensioni personalizzate, come mostrato negli screenshot di seguito.

L'implementazione ha richiesto l'utilizzo sia di CSS che di JavaScript. Usare CSS per riempire l'intero schermo è banale, ma CSS non consente di mantenere lo stesso rapporto larghezza-altezza per evitare di estendere la tela e l'area di gioco. È qui che entra in gioco JavaScript. Puoi ridimensionare gli elementi del documento con JavaScript e attivare il ridimensionamento degli eventi delle finestre.

Preparazione della pagina

Il primo passaggio consiste nel definire l'area della pagina in cui si svolgerà il gioco. Se includi questo blocco come blocco div, puoi inserire altri tag o un elemento canvas al suo interno. Impostati correttamente, questi elementi secondari erediteranno il ridimensionamento del blocco div principale.

Se l'area di gioco è composta da due parti, un'area giochi e un'area per il controllo dei punteggi, l'area potrebbe avere il seguente aspetto:

<div id="gameArea">
  <canvas id="gameCanvas"></canvas>
  <div id="statsPanel"></div>
</div>

Una volta creata la struttura di base del documento, puoi assegnare a questi elementi alcune proprietà CSS per prepararli al ridimensionamento. Molte delle proprietà CSS per "gameArea" sono manipolate direttamente da JavaScript, ma, per farle funzionare, imposta altre proprietà CSS a partire dal blocco div gameArea principale:

#gameArea {
  position: absolute;
  left:     50%;
  top:      50%;
}

L'angolo in alto a sinistra dell'area di disegno viene posizionato al centro dello schermo. La funzione di ridimensionamento automatico di JavaScript descritta nella sezione successiva manipola le proprietà CSS aggiuntive per ridimensionare l'area di gioco e centrarla nella finestra.

Poiché l'area di gioco viene ridimensionata automaticamente in base alle dimensioni della finestra, le dimensioni degli elementi secondari del blocco div gameArea in pixel non devono essere espresse in percentuale. I valori in pixel non consentono la scalabilità degli elementi interni con il div principale quando cambia. Tuttavia, può essere utile iniziare con i pixel e convertirli in percentuali, una volta ottenuto un layout adatto.

Per questo esempio, inizia con l'area di gioco di 300 pixel di altezza e 400 pixel di larghezza. La tela copre l'intera area di gioco e lungo la parte inferiore si trova un riquadro delle statistiche semitrasparente, alto 24 pixel, come mostrato nella Figura 1.

Dimensioni degli elementi secondari gameArea in pixel
Figura 1: dimensioni degli elementi secondari gameArea in pixel

La traduzione di questi valori in percentuali rende la tela al 100% in larghezza e al 100% in altezza (dell'area di gioco, non della finestra). Dividendo 24 per 300 si ottiene l'altezza del riquadro delle statistiche all'8% e, poiché coprirà la parte inferiore dell'area di gioco, anche la larghezza sarà pari al 100%, come si vede nella Figura 2.

Dimensioni degli elementi secondari gameArea in percentuale
Figura 2: dimensioni degli elementi secondari gameArea in percentuale

Ora che hai determinato le dimensioni dell'area di gioco e dei suoi elementi secondari, puoi raggruppare le proprietà CSS dei due elementi interni nel seguente modo:

#gameCanvas {
  width: 100%;
  height: 100%;
}
#statsPanel {
  position: absolute;
  width: 100%;
  height: 8%;
  bottom: 0;
  opacity: 0.8;
}

Ridimensionamento del gioco

Ora è tutto pronto per creare una funzione per gestire il ridimensionamento della finestra. Per prima cosa, recupera un riferimento all'elemento principale del documento gameArea.

var gameArea = document.getElementById('gameArea');

Poiché non ti preoccupa la larghezza o l'altezza esatte, l'informazione successiva che devi impostare è il rapporto tra larghezza e altezza. Usando il riferimento precedente di un'area di gioco di 400 pixel di larghezza e 300 pixel di altezza, sai che vuoi impostare le proporzioni su 4 unità di larghezza e 3 unità di altezza.

var widthToHeight = 4 / 3;

Poiché questa funzione viene richiamata ogni volta che la finestra viene ridimensionata, devi anche recuperare le nuove dimensioni della finestra in modo da poter regolare le dimensioni del gioco di conseguenza. Puoi trovarlo utilizzando le proprietà innerwidth e innerHeight della finestra.

var newWidth = window.innerWidth;
var newHeight = window.innerHeight;

Proprio come hai determinato il rapporto tra larghezza e altezza che desideri, ora puoi determinare il rapporto tra larghezza e altezza corrente della finestra:

var newWidthToHeight = newWidth / newHeight;

Questo ti consente di decidere se il gioco riempirà lo schermo in verticale o in orizzontale, come mostrato nella Figura 3.

Adattare l&#39;elemento gameArea alla finestra mantenendo le proporzioni
Figura 3: adattamento dell'elemento gameArea alla finestra mantenendo le proporzioni

Se la forma dell'area di gioco che ti interessa è più larga della forma della finestra (e l'altezza è più corta), devi riempire la finestra orizzontalmente e lasciare i margini nella parte superiore e inferiore. Analogamente, se la forma dell'area di gioco desiderata è più alta di quella della finestra (e la larghezza è più ristretta), dovrai riempire la finestra in verticale e lasciare margini a sinistra e a destra.

A questo scopo, verifica il rapporto desiderato tra larghezza e altezza con il rapporto larghezza-altezza della finestra corrente e apporta le modifiche appropriate come segue:

if (newWidthToHeight > widthToHeight) {
  // window width is too wide relative to desired game width
  newWidth = newHeight * widthToHeight;
  gameArea.style.height = newHeight + 'px';
  gameArea.style.width = newWidth + 'px';
} else { // window height is too high relative to desired game height
  newHeight = newWidth / widthToHeight;
  gameArea.style.width = newWidth + 'px';
  gameArea.style.height = newHeight + 'px';
}

Ora che hai regolato la larghezza e l'altezza dell'area di gioco, devi centrare gli elementi verso l'alto posizionando un margine negativo nella parte superiore che corrisponde a metà dell'altezza e sulla sinistra che ne occupa metà. Ricorda che CSS posiziona già l'angolo superiore sinistro del div gameArea al centro esatto della finestra, in questo modo l'area di gioco viene centrata all'interno della finestra:

gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';

Puoi anche regolare automaticamente le dimensioni del carattere. Se tutti gli elementi secondari utilizzano em, puoi semplicemente impostare la proprietà CSS fontSize del blocco div gameArea su un valore determinato dalle sue dimensioni.

gameArea.style.fontSize = (newWidth / 400) + 'em';

Infine, vuoi fare in modo che le dimensioni del disegno del canvas corrispondano alla nuova larghezza e altezza. Tieni presente che il resto del codice del gioco deve mantenere le dimensioni del motore grafico separate da quelle del disegno canvas per consentire una risoluzione dinamica della canvas.

var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;

Quindi la funzione di ridimensionamento completata potrebbe avere il seguente aspetto:

function resizeGame() {
    var gameArea = document.getElementById('gameArea');
    var widthToHeight = 4 / 3;
    var newWidth = window.innerWidth;
    var newHeight = window.innerHeight;
    var newWidthToHeight = newWidth / newHeight;
    
    if (newWidthToHeight > widthToHeight) {
        newWidth = newHeight * widthToHeight;
        gameArea.style.height = newHeight + 'px';
        gameArea.style.width = newWidth + 'px';
    } else {
        newHeight = newWidth / widthToHeight;
        gameArea.style.width = newWidth + 'px';
        gameArea.style.height = newHeight + 'px';
    }
    
    gameArea.style.marginTop = (-newHeight / 2) + 'px';
    gameArea.style.marginLeft = (-newWidth / 2) + 'px';
    
    var gameCanvas = document.getElementById('gameCanvas');
    gameCanvas.width = newWidth;
    gameCanvas.height = newHeight;
}

Ora è possibile che queste regolazioni vengano effettuate automaticamente ogni volta che la finestra viene ridimensionata o, nel caso dei dispositivi mobili, dell'orientamento dello schermo. Per gestire questi eventi, fai in modo che chiami la tua funzione ridimensiona Game() in questo modo:

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);

Se la finestra è ridimensionata troppo in alto o se l'orientamento dello schermo è verticale, la larghezza della finestra viene occupata al 100%; se la finestra viene ridimensionata troppo larga o l'orientamento dello schermo è orizzontale, l'altezza della finestra sarà pari al 100%. Le dimensioni rimanenti vengono ridimensionate in base alle proporzioni larghezza-altezza predefinite.

Riepilogo

Gopherwood Studios ha utilizzato versioni di questa struttura per tutti i nostri giochi HTML5 e si è dimostrata molto utile per supportare diverse risoluzioni dello schermo e diversi dispositivi mobili. Inoltre, con l'aiuto di un browser a schermo intero, ciò offre ai nostri giochi web un'esperienza immersiva più simile al gioco per computer tradizionale rispetto a molti giochi basati su browser. Ci auguriamo di ricevere ulteriori innovazioni nei giochi web man mano che le tecnologie HTML5 e web continuano a evolversi.