Авторазмер игр на HTML5

Дерек Детвейлер

Оригинал: http://www.html5rocks.com/en/tutorials/casestudies/gopherwoord-studios-resizing-html5-games.html

Перевод: Влад Мержевич

Летом 2010 года мы создали игру Sand Trap, которую выставили на конкурс игр HTML5 для мобильных телефонов. Но большинство мобильных телефонов отображают только часть игры или делают игру слишком маленькой, что в итоге не позволяет в неё играть. Так что мы взяли на себя ответственность сделать игру плавно регулируемой в зависимости от любого разрешения. После небольшого изменения программы и использования идей изложенных в этой статье, мы получили игру, которая масштабируется в любом современном браузере запущенном на настольном или мобильном устройстве.

Полноэкранный режим Игра в окне браузера

Этот подход хорошо сработал для Sand Trap, поэтому мы использовали тот же метод в нашей последней игре Thwack. Игра автоматически подстраивается под разрешение экрана, чтобы соответствовать полноэкранному режиму и окну произвольного размера, как показано на скриншотах выше.

Для реализации необходимо воспользоваться как CSS, так и JavaScript. Использование CSS для заполнения всего экрана тривиально, но CSS не позволит вам поддерживать аналогичное соотношение ширины к высоте, чтобы предотвратить искажения холста и игрового поля.

Подготовка страницы

Первым шагом следует определить область страницы, где будет выводиться игра. Если вы включите её как <div>, то можете вставлять в этот блок другие теги или элемент <canvas>. Настроив всё правильно, дочерние элементы будут наследовать масштаб родительского <div>.

Если ваше игровое пространство состоит из двух частей — области игры и области счёта, то оно может выглядеть так.

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

Имея базовую структуру документа вы можете задать этим элементам некоторые свойства CSS, чтобы подготовить их для изменения размера. Большинство свойств CSS управляются напрямую через JavaScript, но чтобы это работало, установим несколько свойств CSS для родителя gameArea.

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

Этот стиль переместит левый верхний угол холста в центр экрана. Функция JavaScript авторазмера, описанная в следующем разделе, управляет дополнительными свойствами CSS для изменения размера области игры и центрирования её в окне.

Поскольку игровая область автоматически изменяется в зависимости от размеров окна, то вы не хотите использовать для дочерних элементов gameArea в качестве единиц пикселы, а захотите использовать проценты. Значения в пикселах не позволяют внутренним элементам масштабироваться вместе с родительским <div> при его изменении. Тем не менее, может быть полезно начать с пикселов, а затем перевести размеры в проценты, если у вас есть макет, который вам нравится.

Например, начнём с игровой области 300 пикселов в высоту и 400 в ширину. Холст занимает доступную область игры, а полупрозрачная панель состояния высотой 24 пиксела располагается внизу, как показано на рис. 1.

Размеры дочерних элементов gameArea в пикселах

Рис. 1. Размеры дочерних элементов gameArea в пикселах

Переводя эти значения в проценты делаем холст 100% в ширину и 100% в высоту (от gameArea, а не окна). Деление 24 на 300 даёт высоту панели состояния 8%, а поскольку она будет занимать всю нижнюю часть игрового поля, её ширина будет 100%, как показано на рис. 2.

Размеры дочерних элементов gameArea в процентах

Рис. 2. Размеры дочерних элементов gameArea в процентах

Теперь, когда вы определили размеры игровой области и её дочерних элементов, вы можете собрать вместе свойства CSS для двух внутренних элементов:

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

Изменение размеров игры

Теперь вы готовы к созданию функции для обработки изменения размеров окна. Вначале указываем ссылку на родительский элемент gameArea.

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

Поскольку вы не озаботились указанием точной ширины или высоты, далее следует установить их пропорции. Используя ваши ранние значения игровой области 400 пикселов в ширину и 300 в высоту, вы хотите задать соотношения сторон 4 к 3.

var widthToHeight = 4 / 3;

Так как функция вызывается при изменении размеров окна, вам надо получить новые размеры окна, чтобы соответственно настроить размеры вашей игры. Это можно сделать с помощью свойств innerWidth и innerHeight.

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

Подобно тому, как вы определили соотношение желаемой ширины и высоты, так же вы можете определить соотношение текущей ширины к высоте окна.

var newWidthToHeight = newWidth / newHeight;

Это позволит вам решить, следует ли сделать игру на весь экран вертикально или горизонтально, как показано на рис. 3.

Установка элемента gameArea в окне с сохранением пропорций

Рис. 3. Установка элемента gameArea в окне с сохранением пропорций

Если желаемая форма игровой области шире, чем форма окна (и меньше высоты), вам нужно заполнить окно по горизонтали и оставить поля сверху и снизу. Аналогично, если желаемая форма игровой области выше, чем форма окна (и у́же ширины), вам необходимо заполнить окно по вертикали и оставить поля слева и справа.

Для этого сравните желаемое соотношение ширины к высоте с соотношением ширины к высоте текущего окна и внесите такие соответствующие корректировки:

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

Вы также можете автоматически настроить размер шрифта. Если все дочерние элементы используют em, достаточно установить свойство fontSize для блока gameArea в значение определяющее его размер.

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

Напоследок вы хотите, чтобы размеры холста рисования соответствовали своей новой ширине и высоте. Обратите внимание, что часть игрового кода должна быть отделена от установки размеров холста, чтобы учесть динамическое разрешение холста.

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

Итак, конечная функция изменения размеров может выглядеть примерно так:

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

Теперь вы хотите, чтобы настройки применялись автоматически при изменении размеров окна или, в случае с мобильными устройствами, при смене ориентации экрана.

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
Если размер окна по высоте слишком большой или устройство ориентировано вертикально, вы делаете ширину 100% от окна, если размер окна слишком широкий или экран ориентирован горизонтально, вы делаете высоту 100% от окна. Другое значение размера вычисляется в соответствии с соотношением ширины к высоте.

Резюме

Gopherwood Studios использовала версии этой структуры для всех своих игр HTML5 и это оказалось весьма полезным для примирения множества разрешений экранов и разных мобильных устройств. Кроме того, с помощью полноэкранного режима браузера наши веб-игры дают захватывающий опыт, больше похожий на традиционные настольные игры, чем большинство браузерных игр. Мы с нетерпением ожидаем больше инноваций в веб-играх и наблюдаем как HTML5 и веб-технологии продолжают развиваться.

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.