Fallstudie: Größe von HTML5-Spielen automatisch anpassen

Derek Detweiler
Derek Detweiler

Einleitung

Im Sommer 2010 haben wir Sand Trap entwickelt, ein Spiel, für das wir an einem Wettbewerb zu HTML5-Spielen für Mobiltelefone teilgenommen haben. Auf den meisten Smartphones wurde jedoch nur ein Teil des Spiels gezeigt oder war das Spiel zu klein, sodass es überhaupt nicht gespielt werden konnte. Also haben wir es uns zur Aufgabe gemacht, das Spiel reibungslos an jede Auflösung anzupassen. Nach ein wenig Neuprogrammierung und den in diesem Artikel beschriebenen Ideen entwickelten wir ein Spiel, das für jeden modernen Browser geeignet war, ob auf einem Desktop-Computer oder einem Mobilgerät.

Screenshot von thwack-Vollbild
Screenshot von „Twack“ im Browserfenster

Dieser Ansatz funktionierte gut bei Sand Trap, also haben wir dieselbe Methode bei unserem neuesten Spiel „Twack!“ verwendet. Das Spiel passt die Bildschirmauflösung automatisch an Vollbild- und benutzerdefinierte Fenster an, wie in den folgenden Screenshots gezeigt.

Für die Implementierung waren CSS und JavaScript erforderlich. Die Verwendung von CSS zum Ausfüllen des gesamten Bildschirms ist einfach, aber CSS erlaubt es nicht, das gleiche Breite-zu-Höhe-Verhältnis beizubehalten, um eine Streckung des Canvas und des Spielebereichs zu verhindern. Hier kommt JavaScript ins Spiel. Sie können Dokumentelemente mit JavaScript neu skalieren und die Größenanpassung bei Fensterereignissen auslösen.

Seite vorbereiten

Der erste Schritt besteht darin, den Bereich auf der Seite festzulegen, in dem das Spiel gespielt wird. Wenn Sie diesen als div-Block einfügen, können Sie andere Tags oder ein Canvas-Element darin platzieren. Bei korrekter Einrichtung übernehmen diese untergeordneten Elemente die Skalierung des übergeordneten div-Blocks.

Wenn Ihr Spielbereich zwei Teile, einen Spielbereich und einen Bereich zur Punkteführung hat, könnte dies so aussehen:

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

Sobald Sie eine grundlegende Dokumentstruktur haben, können Sie diesen Elementen einige CSS-Eigenschaften zuweisen, um sie für die Größenanpassung vorzubereiten. Viele der CSS-Eigenschaften für „gameArea“ werden direkt durch JavaScript geändert. Damit sie funktionieren, müssen Sie jedoch einige andere CSS-Eigenschaften einrichten. Beginnen Sie dabei mit dem übergeordneten div-Block „gameArea“:

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

Dadurch wird die obere linke Ecke des Canvas in der Bildschirmmitte platziert. Die JavaScript-Funktion zur automatischen Größenanpassung, die im nächsten Abschnitt beschrieben wird, verändert zusätzliche CSS-Eigenschaften, um die Größe des Spielbereichs zu ändern und im Fenster zu zentrieren.

Da die Größe des Spielbereichs automatisch an die Abmessungen des Fensters angepasst wird, möchten Sie die Abmessungen für die untergeordneten Elemente des div-Blocks „gameArea“ nicht in Pixeln, sondern in Prozentsätzen. Pixelwerte lassen nicht zu, dass innere Elemente mit dem übergeordneten div-Element skaliert werden, wenn es sich ändert. Es kann jedoch hilfreich sein, mit Pixeln zu beginnen und diese dann in Prozentsätze umzuwandeln, sobald Sie ein Layout haben, das Ihnen gefällt.

Beginnen Sie für dieses Beispiel mit einer Höhe von 300 Pixeln und einer Breite von 400 Pixeln. Der Canvas füllt den gesamten Spielebereich aus und am unteren Rand verläuft ein halbtransparentes Statistikfeld mit einer Höhe von 24 Pixeln, wie in Abbildung 1 dargestellt.

Abmessungen der untergeordneten Elemente von gameArea in Pixeln
Abbildung 1: Dimensionen der untergeordneten Elemente von gameArea in Pixeln

Werden diese Werte in Prozentsätze umgewandelt, erhält der Canvas eine Breite von 100% und eine Höhe von 100 % (von gameArea und nicht von Fenster). Durch die Division von 24 durch 300 beträgt die Höhe des Bereichs mit Statistiken 8 %. Da er den unteren Teil des Spielbereichs abdeckt, beträgt seine Breite ebenfalls 100 % (siehe Abbildung 2).

Dimensionen der untergeordneten „gameArea“-Elemente in Prozent
Abbildung 2: Dimensionen der untergeordneten Elemente von gameArea in Prozent

Nachdem Sie nun die Abmessungen der Spielfläche und der untergeordneten Elemente festgelegt haben, können Sie die CSS-Eigenschaften für die beiden inneren Elemente wie folgt zusammenstellen:

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

Größe des Spiels anpassen

Jetzt können Sie eine Funktion erstellen, mit der die Größe des Fensters gehandhabt wird. Rufen Sie zunächst einen Verweis auf das übergeordnete gameArea-Dokumentelement ab.

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

Da es Ihnen nicht um die genaue Breite oder Höhe geht, müssen Sie als Nächstes das Verhältnis von Breite zu Höhe festlegen. Wie Sie bereits von einem Spielebereich mit einer Breite von 400 Pixeln und einer Höhe von 300 Pixeln gelernt haben, wissen Sie, dass Sie ein Seitenverhältnis von 4 Einheiten breit und 3 Einheiten hoch festlegen möchten.

var widthToHeight = 4 / 3;

Da diese Funktion bei jeder Größenanpassung des Fensters aufgerufen wird, sollten Sie auch die neuen Abmessungen des Fensters erfassen, damit Sie die Abmessungen Ihres Spiels entsprechend anpassen können. Sie finden dies mithilfe der Eigenschaften „innerWidth“ und „innerHeight“ des Fensters.

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

So wie Sie das gewünschte Verhältnis von Breite zu Höhe festgelegt haben, können Sie jetzt das aktuelle Breite-zu-Höhe-Verhältnis des Fensters bestimmen:

var newWidthToHeight = newWidth / newHeight;

So können Sie entscheiden, ob das Spiel den Bildschirm vertikal oder horizontal ausfüllen soll (siehe Abbildung 3).

GameArea-Element an Fenster unter Beibehaltung des Seitenverhältnisses anpassen
Abbildung 3: GameArea-Element unter Beibehaltung des Seitenverhältnisses an das Fenster anpassen

Wenn die gewünschte Form des Spielbereichs breiter als die Form des Fensters und die Höhe kürzer ist, muss das Fenster horizontal ausgefüllt und oben und unten frei gelassen werden. Ist die gewünschte Form des Spielbereichs höher als die Form des Fensters (und die Breite schmaler), müssen Sie das Fenster vertikal ausfüllen und Ränder links und rechts lassen.

Testen Sie dazu das gewünschte Verhältnis von Breite zu Höhe mit dem Verhältnis von Breite zu Höhe des aktuellen Fensters und nehmen Sie die entsprechenden Anpassungen vor:

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';
}

Nachdem Sie die Breite und Höhe des Spielebereichs angepasst haben, müssen Sie die Elemente zentrieren, indem Sie oben einen negativen Rand platzieren, der die Hälfte der Höhe und links die Hälfte der Breite entspricht. Denken Sie daran, dass CSS die obere linke Ecke des gameArea-div-Elements bereits genau in der Mitte des Fensters platziert. Dadurch wird der Spielbereich im Fenster zentriert:

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

Außerdem wäre es sinnvoll, die Schriftgröße automatisch anzupassen. Wenn alle untergeordneten Elemente den Parameter „em“ verwenden, können Sie einfach die CSS-Eigenschaft „fontSize“ des div-Blocks „gameArea“ auf einen Wert setzen, der durch seine Größe bestimmt wird.

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

Schließlich möchten Sie die Abmessungen der Canvas-Zeichnung so anpassen, dass sie der neuen Breite und Höhe entsprechen. Der restliche Spielcode muss die Abmessungen der Spiel-Engine von den Abmessungen der Canvas-Zeichnung trennen, damit eine dynamische Canvas-Auflösung möglich ist.

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

Die fertige Funktion zur Größenanpassung könnte also in etwa so aussehen:

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;
}

Jetzt möchten Sie, dass diese Anpassungen automatisch erfolgen, wenn die Größe des Fensters oder, im Falle von Mobilgeräten, die Bildschirmausrichtung geändert wird. Behandeln Sie diese Ereignisse, indem Sie Ihre Funktion „resizeGame()“ so aufrufen:

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

Wenn die Größe des Fensters zu hoch oder die Bildschirmausrichtung vertikal ist, legen Sie die Breite auf 100% des Fensters fest. Wenn die Größe des Fensters zu breit oder die Bildschirmausrichtung horizontal ist, entspricht die Höhe 100% des Fensters. Die übrigen Abmessungen werden entsprechend dem vorgegebenen Breite-zu-Höhe-Seitenverhältnis bemessen.

Zusammenfassung

Gopherwood Studios hat Versionen dieser Struktur für alle unsere HTML5-Spiele verwendet und hat sich als sehr nützlich für verschiedene Bildschirmauflösungen und verschiedene Mobilgeräte erwiesen. Darüber hinaus erhalten unsere Webspiele dank eines Vollbild-Browsers ein immersives Erlebnis, das eher dem herkömmlichen Desktop-Gaming ähnelt als viele browserbasierte Spiele. Im Zuge der Weiterentwicklung von HTML5 und Webtechnologien freuen wir uns auf weitere Innovationen bei Webspielen.