Studium przypadku – automatyczna zmiana rozmiaru gier na HTML5

Derek Detweiler
Derek Detweiler

Wprowadzenie

Latem 2010 r. stworzyliśmy Sand Trap, grę, którą zgłosiliśmy do konkursu na gry HTML5 na telefony komórkowe. Jednak większość telefonów komórkowych wyświetlała tylko część gry lub robiła ją zbyt małą, przez co nie dało się w nią grać. Dlatego postanowiliśmy, że gra będzie się płynnie dostosowywać do dowolnej rozdzielczości. Po pewnym przeprogramowaniu i zaimplementowaniu pomysłów opisanych w tym artykule gra działała w każdej nowoczesnej przeglądarce, niezależnie od tego, czy była uruchamiana na komputerze czy urządzeniu mobilnym.

Zrzut ekranu z Thwack w trybie pełnoekranowym
Zrzut ekranu przedstawiający thwack w mniejszym oknie przeglądarki

To podejście sprawdziło się w przypadku Sand Trap, więc zastosowaliśmy je w naszej najnowszej grze, Thwack!. Gra automatycznie dostosowuje rozdzielczość ekranu do pełnoekranowego i niestandardowego okna, jak widać na zrzutach ekranu poniżej.

Wdrożenie tego wymagało korzystania zarówno z CSS, jak i JavaScriptu. Wypełnienie całego ekranu za pomocą kodu CSS jest proste, ale kod ten nie pozwala zachować tego samego współczynnika proporcji szerokości do wysokości, aby zapobiec rozciąganiu się płótna i obszaru gry. Tutaj do gry wchodzi JavaScript. Za pomocą JavaScript możesz zmieniać rozmiar elementów dokumentu i uruchamiać zdarzenia zmiany rozmiaru w oknie.

Przygotowywanie strony

Pierwszym krokiem jest wyznaczenie obszaru na stronie, na którym będzie rozgrywać się gra. Jeśli umieścisz go jako blok div, możesz umieścić w nim inne tagi lub element kanwy. Po prawidłowej konfiguracji te elementy podrzędne odziedziczą skalowanie bloku div nadrzędnego.

Jeśli obszar gry jest podzielony na 2 części – obszar gry i obszar punktacji – może wyglądać tak:

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

Gdy już masz podstawową strukturę dokumentu, możesz przypisać tym elementom kilka właściwości CSS, aby przygotować je do zmiany rozmiaru. Wiele właściwości CSS „gameArea” jest modyfikowanych bezpośrednio przez JavaScript, ale aby działały, skonfiguruj kilka innych właściwości CSS, zaczynając od nadrzędnego bloku div gameArea:

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

W ten sposób lewy górny róg płótna znajdzie się na środku ekranu. Funkcja JavaScript do automatycznego dostosowywania rozmiaru opisana w następnej sekcji manipuluje dodatkowymi właściwościami CSS, aby dostosować rozmiar obszaru gry i wyśrodkować go w oknie.

Ponieważ rozmiar obszaru gry jest automatycznie dostosowywany do wymiarów okna, nie chcesz, aby wymiary elementów podrzędnych bloku div gameArea były podawane w pikselach. Zamiast tego chcesz, aby były one podawane w procentach. Wartości pikseli nie pozwalają na skalowanie elementów wewnętrznych wraz ze zmianami w elemencie nadrzędnym. Może jednak być przydatne, aby zacząć od pikseli, a potem, gdy już wybierzesz odpowiedni układ, przekonwertować je na wartości procentowe.

W tym przykładzie zacznij od obszaru gry o wysokości 300 pikseli i szerokości 400 pikseli. Płótno pokrywa cały obszar gry, a półprzezroczysty panel statystyk ma wysokość 24 piksele i znajduje się u dołu ekranu (patrz rys. 1).

Wymiary elementów podrzędnych obszaru gry w pikselach
Rysunek 1. Wymiary elementów podrzędnych gameArea w pikselach

Przekształcanie tych wartości na procenty powoduje, że szerokość i wysokość canvasa wynoszą 100% (w przypadku obszaru gry, a nie okna). Dzielenie 24 przez 300 daje wysokość panelu statystyk wynoszącą 8%. Ponieważ panel ma zakrywać dolną część obszaru gry, jego szerokość również wynosi 100%, jak widać na rysunku 2.

Wymiary elementów podrzędnych gameArea w procentach
Rysunek 2. Wymiary elementów podrzędnych gameArea w procentach

Po określeniu wymiarów obszaru gry i jego elementów potomnych możesz utworzyć właściwości CSS dla 2 elementów wewnętrznych w ten sposób:

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

Zmienianie rozmiaru gry

Teraz możesz utworzyć funkcję, która będzie obsługiwać zmianę rozmiaru okna. Najpierw pobierz odwołanie do nadrzędnego elementu dokumentu gameArea.

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

Ponieważ nie interesuje Cię dokładna szerokość ani wysokość, następną informacją, którą musisz ustawić, jest stosunek szerokości do wysokości. Z poprzednio podanych informacji o tym, że obszar gry ma 400 pikseli szerokości i 300 pikseli wysokości, wynika, że chcesz ustawić współczynnik proporcji na 4 jednostki szerokości i 3 jednostki wysokości.

var widthToHeight = 4 / 3;

Ta funkcja jest wywoływana za każdym razem, gdy zmienia się rozmiar okna, więc musisz też pobrać nowe wymiary okna, aby móc dostosować wymiary gry. Aby to sprawdzić, użyj właściwości innerWidth i innerHeight okna.

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

Podobnie jak w przypadku określenia pożądanego stosunku szerokości do wysokości, możesz teraz określić bieżący stosunek szerokości do wysokości okna:

var newWidthToHeight = newWidth / newHeight;

Dzięki temu możesz zdecydować, czy gra ma wypełniać ekran w pionie czy w poziomie (patrz rysunek 3).

Dopasowanie elementu gameArea do okna przy zachowaniu współczynnika proporcji
Rysunek 3. Dopasowanie elementu gameArea do okna przy zachowaniu współczynnika proporcji

Jeśli kształt obszaru gry jest szerszy niż kształt okna (a wysokość jest krótsza), musisz wypełnić okno w poziomie i zostawić marginesy u góry i u dołu. Podobnie, jeśli kształt obszaru gry jest wyższy niż kształt okna (a szerokość jest węższa), musisz wypełnić okno w pionie i zostawić marginesy po lewej i po prawej stronie.

Aby to zrobić, przetestuj pożądany stosunek szerokości do wysokości w porównaniu ze stosunkiem szerokości do wysokości bieżącego okna i wprowadź odpowiednie zmiany w ten sposób:

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

Po dostosowaniu szerokości i wysokości obszaru gry musisz wyśrodkować elementy, umieszczając na górze ujemszy margines o połowie wysokości, a z lewej strony o połowie szerokości. Pamiętaj, że CSS umieszcza już lewy górny róg elementu div gameArea dokładnie na środku okna, więc dzięki temu obszar gry będzie wyśrodkowany w oknie:

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

Warto też automatycznie dostosowywać rozmiar czcionki. Jeśli wszystkie elementy podrzędne używają jednostki em, możesz po prostu ustawić właściwość CSS fontSize elementu div gameArea na wartość określoną przez jego rozmiar.

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

Na koniec dopasuj wymiary rysunku na płótnie do jego nowej szerokości i wysokości. Pamiętaj, że pozostała część kodu gry musi zachować wymiary silnika gry oddzielnie od wymiarów rysunku na płótnie, aby uwzględnić dynamiczną rozdzielczość płóta.

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

Ukończona funkcja zmiany rozmiaru może wyglądać tak:

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

Chcesz, aby te zmiany były wprowadzane automatycznie po zmianie rozmiaru okna lub, w przypadku urządzeń mobilnych, po zmianie orientacji ekranu. Aby obsłużyć te zdarzenia, wywołuj funkcję resizeGame() w taki sposób:

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

Jeśli okno jest zbyt wysokie lub ekran jest w orientacji pionowej, ustawiasz szerokość na 100% szerokości okna, a jeśli okno jest zbyt szerokie lub ekran jest w orientacji poziomej, ustawiasz wysokość na 100% wysokości okna. Pozostały wymiar jest dostosowywany zgodnie z wstępnie określonym współczynnikiem proporcji szerokości do wysokości.

Podsumowanie

Studio Gopherwood używało tej struktury we wszystkich swoich grach HTML5. Okazała się ona bardzo przydatna w przypadku różnych rozdzielczości ekranu i różnych urządzeń mobilnych. Dodatkowo dzięki przeglądarce na pełnym ekranie nasze gry internetowe są bardziej wciągające niż wiele gier opartych na przeglądarce i przypominają bardziej tradycyjne gry na komputery. Z niecierpliwością czekamy na kolejne innowacje w grach internetowych, które będą wynikać z dalszego rozwoju HTML5 i technologii internetowych.