Caso de éxito: Ajuste automático del tamaño de los juegos HTML5

Derek Detweiler
Derek Detweiler

Introducción

En el verano de 2010, creamos Sand Trap, un juego que presentamos en una competencia de juegos HTML5 para teléfonos celulares. Sin embargo, la mayoría de los teléfonos celulares solo mostraban una parte del juego o lo hacían demasiado pequeño, por lo que no se podía jugar. Por lo tanto, nos encargamos de que el juego se ajuste de forma fluida para que coincida con cualquier resolución. Después de un poco de reprogramación y de usar las ideas que se describen en este artículo, teníamos un juego que se ajustaba a cualquier navegador moderno, ya sea que se ejecutara en una computadora de escritorio o en un dispositivo móvil.

Captura de pantalla de la pantalla completa de Thwack
captura de pantalla de thwack más pequeña en la ventana del navegador

Este enfoque funcionó bien para Sand Trap, por lo que usamos el mismo método en nuestro juego más reciente, Thwack!. El juego ajusta automáticamente las resoluciones de pantalla para que se ajusten a ventanas de pantalla completa y de tamaño personalizado, como se muestra en las siguientes capturas de pantalla.

Para implementar esto, fue necesario aprovechar CSS y JavaScript. Usar CSS para llenar toda la pantalla es trivial, pero CSS no te permite mantener la misma relación de ancho a altura para evitar que se estire el lienzo y el área de juego. Ahí es donde entra en juego JavaScript. Puedes volver a escalar los elementos del documento con JavaScript y activar el cambio de tamaño en los eventos de ventana.

Prepara la página

El primer paso es designar el área de la página en la que se llevará a cabo el juego. Si lo incluyes como un bloque div, puedes colocar otras etiquetas o un elemento de lienzo dentro de él. Si lo configuras correctamente, estos elementos secundarios heredarán la escala del bloque de div superior.

Si tu área de juego tiene dos partes, una de juego y otra de registro de puntuación, podría verse de la siguiente manera:

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

Una vez que tengas una estructura de documento básica, puedes asignarles a estos elementos algunas propiedades CSS para prepararlos para cambiar de tamaño. JavaScript manipula directamente muchas de las propiedades CSS de “gameArea”, pero para que funcionen, configura algunas otras propiedades CSS, comenzando por el bloque de div gameArea superior:

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

Esto coloca la esquina superior izquierda del lienzo en el centro de la pantalla. La función de cambio de tamaño automático de JavaScript que se describe en la siguiente sección manipula propiedades adicionales de CSS para cambiar el tamaño del área de juego y centrarla en la ventana.

Dado que el área de juego cambia de tamaño automáticamente según las dimensiones de la ventana, no quieres que las dimensiones de los elementos secundarios del bloque de div gameArea sean en píxeles, sino en porcentajes. Los valores de píxeles no permiten que los elementos internos se ajusten con el div superior a medida que cambia. Sin embargo, puede ser útil comenzar con píxeles y, luego, convertirlos en porcentajes una vez que tengas un diseño que te guste.

En este ejemplo, comienza con un área de juego de 300 píxeles de alto y 400 píxeles de ancho. El lienzo cubre toda el área del juego y un panel de estadísticas semitransparente se extiende a lo largo de la parte inferior con 24 píxeles de altura, como se muestra en la Figura 1.

Dimensiones de los elementos secundarios de gameArea en píxeles
Figura 1: Dimensiones de los elementos secundarios de gameArea en píxeles

Si traduces estos valores a porcentajes, el lienzo tendrá un 100% de ancho y un 100% de altura (de gameArea, no de la ventana). Si divides 24 por 300, obtienes el 8% como altura del panel de estadísticas y, como cubrirá la parte inferior del área de juego, su ancho también será del 100%, como se ve en la Figura 2.

Dimensiones de los elementos secundarios de gameArea en porcentajes
Figura 2: Dimensiones de los elementos secundarios de gameArea en porcentajes

Ahora que determinaste las dimensiones del área de juego y sus elementos secundarios, puedes reunir las propiedades CSS de los dos elementos internos de la siguiente manera:

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

Cambia el tamaño del juego

Ya puedes crear una función para controlar el cambio de tamaño de la ventana. Primero, toma una referencia al elemento del documento gameArea superior.

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

Como no te preocupa el ancho o la altura exactos, la siguiente información que debes establecer es la proporción entre el ancho y la altura. Con la referencia anterior de un área de juego de 400 píxeles de ancho y 300 píxeles de alto, sabes que quieres establecer la relación de aspecto en 4 unidades de ancho y 3 unidades de alto.

var widthToHeight = 4 / 3;

Como se llama a esta función cada vez que se cambia el tamaño de la ventana, también debes obtener las dimensiones nuevas de la ventana para poder ajustar las dimensiones del juego para que coincidan. Para ello, usa las propiedades innerWidth y innerHeight de la ventana.

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

Así como determinaste la relación de ancho y alto que deseas, ahora puedes determinar la relación de ancho y alto actual de la ventana:

var newWidthToHeight = newWidth / newHeight;

Esto te permite decidir si quieres que el juego ocupe la pantalla vertical o horizontalmente, como se muestra en la Figura 3.

Cómo ajustar el elemento gameArea a la ventana y mantener la relación de aspecto
Figura 3: Cómo ajustar el elemento gameArea a la ventana y mantener la relación de aspecto

Si la forma del área de juego deseada es más ancha que la forma de la ventana (y la altura es más corta), debes completar la ventana horizontalmente y dejar márgenes en la parte superior e inferior. Del mismo modo, si la forma del área de juego deseada es más alta que la forma de la ventana (y el ancho es más estrecho), debes completar la ventana verticalmente y dejar márgenes a la izquierda y a la derecha.

Para ello, prueba la relación de ancho y alto deseada con la relación de ancho y alto de la ventana actual y realiza los ajustes adecuados de la siguiente manera:

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

Ahora que ajustaste el ancho y la altura del área de juego, debes centrar los elementos colocando un margen negativo en la parte superior que sea la mitad de la altura y en la izquierda que sea la mitad del ancho. Recuerda que CSS ya coloca la esquina superior izquierda del div gameArea en el centro exacto de la ventana, por lo que se centra el área de juego en la ventana:

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

También querrás ajustar automáticamente el tamaño de la fuente. Si todos los elementos secundarios usan em, puedes configurar la propiedad CSS fontSize del bloque div gameArea en un valor determinado por su tamaño.

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

Por último, debes hacer que las dimensiones del dibujo del lienzo coincidan con su nuevo ancho y alto. Ten en cuenta que el resto del código del juego debe mantener las dimensiones del motor de juego separadas de las dimensiones de dibujo del lienzo para adaptarse a una resolución de lienzo dinámica.

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

Por lo tanto, la función de cambio de tamaño completada podría verse de la siguiente manera:

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

Ahora, quieres que estos ajustes se realicen automáticamente cada vez que se cambie el tamaño de la ventana o, en el caso de los dispositivos móviles, la orientación de la pantalla. Para controlar estos eventos, haz que llamen a tu función resizeGame() de la siguiente manera:

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

Si el tamaño de la ventana es demasiado alto o la orientación de la pantalla es vertical, el ancho será del 100% de la ventana. Si el tamaño de la ventana es demasiado ancho o la orientación de la pantalla es horizontal, la altura será del 100% de la ventana. El tamaño de la dimensión restante se ajusta según la relación de aspecto predeterminada de ancho a alto.

Resumen

Gopherwood Studios usó versiones de esta estructura para todos nuestros juegos HTML5, y resultó muy útil para adaptarse a varias resoluciones de pantalla y varios dispositivos móviles. Además, con la ayuda de un navegador de pantalla completa, nuestros juegos web ofrecen una experiencia envolvente más similar a los juegos tradicionales para computadoras de escritorio que muchos juegos basados en navegadores. Esperamos ver más innovaciones en los juegos web a medida que HTML5 y las tecnologías web sigan evolucionando.