Introdução
No verão de 2010, criamos o Sand Trap, um jogo que inscrevemos em uma competição de jogos HTML5 para smartphones. No entanto, a maioria dos smartphones mostrava apenas parte do jogo ou o deixava muito pequeno, o que tornava impossível jogar. Por isso, decidimos fazer o jogo se ajustar de forma fluida a qualquer resolução. Depois de um pouco de reprogramação e usando as ideias descritas neste artigo, criamos um jogo que foi dimensionado para qualquer navegador moderno, seja em um computador ou dispositivo móvel.


Essa abordagem funcionou bem para o Sand Trap, então usamos o mesmo método no nosso jogo mais recente, o Thwack!. O jogo ajusta automaticamente as resoluções da tela para caber em janelas em tela cheia e personalizadas, conforme mostrado nas capturas de tela abaixo.
Para implementar isso, foi necessário aproveitar o CSS e o JavaScript. Usar CSS para preencher toda a tela é trivial, mas o CSS não permite manter a mesma proporção de largura para altura para evitar o alongamento da tela e da área do jogo. É aí que entra o JavaScript. É possível redimensionar elementos de documentos com JavaScript e acionar o redimensionamento em eventos de janela.
Como preparar a página
A primeira etapa é designar a área na página em que o jogo vai acontecer. Se você incluir isso como um bloco div, poderá colocar outras tags ou um elemento de tela nele. Ao configurar corretamente, esses elementos filhos herdam a escala do bloco div pai.
Se você tiver duas partes na área de jogo, uma área de jogo e uma área de pontuação, elas podem ser assim:
<div id="gameArea">
<canvas id="gameCanvas"></canvas>
<div id="statsPanel"></div>
</div>
Depois de ter uma estrutura de documento básica, você pode atribuir a esses elementos algumas propriedades CSS para prepará-los para o redimensionamento. Muitas das propriedades CSS de "gameArea" são manipuladas diretamente pelo JavaScript, mas, para que elas funcionem, configure algumas outras propriedades CSS começando com o bloco div gameArea pai:
#gameArea {
position: absolute;
left: 50%;
top: 50%;
}
Isso coloca o canto superior esquerdo da tela no centro da tela. A função de redimensionamento automático do JavaScript descrita na próxima seção manipula outras propriedades do CSS para redimensionar a área do jogo e centralizá-la na janela.
Como a área do jogo é redimensionada automaticamente de acordo com as dimensões da janela, não use as dimensões em pixels para os elementos filhos do bloco div gameArea. Use porcentagens. Os valores de pixel não permitem que os elementos internos sejam dimensionados com a div pai conforme ela muda. No entanto, pode ser útil começar com pixels e depois convertê-los em porcentagens quando você tiver um layout que goste.
Para este exemplo, comece com a área do jogo com 300 pixels de altura e 400 pixels de largura. A tela cobre toda a área do jogo, e um painel de estatísticas semitransparente é exibido na parte de baixo com 24 pixels de altura, conforme mostrado na Figura 1.

A conversão desses valores em porcentagens faz com que a tela tenha 100% de largura e 100% de altura (da gameArea, não da janela). A divisão de 24 por 300 resulta em uma altura de 8% para o painel de estatísticas. Como ele vai cobrir a parte de baixo da área do jogo, a largura também será de 100%, como mostrado na Figura 2.

Agora que você determinou as dimensões da área de jogo e os elementos filhos, pode montar as propriedades CSS dos dois elementos internos da seguinte maneira:
#gameCanvas {
width: 100%;
height: 100%;
}
#statsPanel {
position: absolute;
width: 100%;
height: 8%;
bottom: 0;
opacity: 0.8;
}
Redimensionar o jogo
Agora você está pronto para criar uma função para processar a janela que está sendo redimensionada. Primeiro, encontre uma referência ao elemento pai do documento gameArea.
var gameArea = document.getElementById('gameArea');
Como você não precisa se preocupar com a largura ou altura exata, a próxima informação que precisa definir é a proporção entre largura e altura. Usando sua referência anterior de uma área de jogo de 400 pixels de largura e 300 pixels de altura, você sabe que quer definir a proporção em 4 unidades de largura e 3 unidades de altura.
var widthToHeight = 4 / 3;
Como essa função é chamada sempre que a janela é redimensionada, você também precisa extrair as novas dimensões da janela para poder ajustar as dimensões do jogo. Para encontrar isso, use as propriedades innerWidth e innerHeight da janela.
var newWidth = window.innerWidth;
var newHeight = window.innerHeight;
Assim como você determinou a proporção de largura para altura que queria, agora você pode determinar a proporção de largura para altura atual da janela:
var newWidthToHeight = newWidth / newHeight;
Isso permite que você decida se o jogo vai preencher a tela verticalmente ou horizontalmente, conforme mostrado na Figura 3.

Se a forma da área do jogo desejada for mais larga que a da janela (e a altura for menor), você precisará preencher a janela horizontalmente e deixar margens na parte de cima e de baixo. Da mesma forma, se a forma da área do jogo desejada for maior que a da janela (e a largura for mais estreita), você precisará preencher a janela verticalmente e deixar margens à esquerda e à direita.
Para fazer isso, teste a proporção desejada de largura para altura com a proporção de largura para altura da janela atual e faça os ajustes adequados da seguinte maneira:
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';
}
Agora que você ajustou a largura e a altura da área do jogo, é necessário centralizar as coisas colocando uma margem negativa na parte de cima que seja metade da altura e na esquerda que seja metade da largura. Lembre-se de que o CSS já está colocando o canto superior esquerdo da div gameArea no centro exato da janela. Isso centraliza a área do jogo na janela:
gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';
Você também precisa ajustar automaticamente o tamanho da fonte. Se todos os elementos filhos usarem em, basta definir a propriedade CSS fontSize do bloco div gameArea para um valor determinado pelo tamanho.
gameArea.style.fontSize = (newWidth / 400) + 'em';
Por fim, você quer que as dimensões do desenho da tela correspondam à nova largura e altura. O restante do código do jogo precisa manter as dimensões do mecanismo do jogo separadas das dimensões de desenho da tela para acomodar uma resolução de tela dinâmica.
var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;
A função de redimensionamento concluída pode ficar assim:
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;
}
Agora, você quer que esses ajustes sejam feitos automaticamente sempre que a janela for redimensionada ou, no caso de dispositivos móveis, a orientação da tela for alterada. Processe esses eventos fazendo com que eles chamem a função resizeGame() desta forma:
window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
Se a janela for redimensionada para ficar muito alta ou a orientação da tela for vertical, você vai definir a largura como 100% da janela. Se a janela for redimensionada para ficar muito larga ou a orientação da tela for horizontal, você vai definir a altura como 100% da janela. A dimensão restante é dimensionada de acordo com a proporção de largura para altura predeterminada.
Resumo
A Gopherwood Studios usou versões dessa estrutura em todos os nossos jogos HTML5, e ela se mostrou muito útil para acomodar várias resoluções de tela e vários dispositivos móveis. Além disso, com a ajuda de um navegador em tela cheia, isso oferece aos nossos jogos da Web uma experiência imersiva mais semelhante aos jogos tradicionais para computador do que muitos jogos baseados em navegador. Esperamos mais inovações nos jogos da Web à medida que o HTML5 e as tecnologias da Web continuarem evoluindo.