Hacer un juego HTML5 sin motor y sin framework
· 3 min de lectura
Seis de los nueve primeros juegos de nuestra página de juegos se publican sin ninguna dependencia de ningún tipo: ni motor, ni framework, ni librería en tiempo de build. El más pequeño, Reefhold, ocupa 63 KB en disco: el juego entero, arte incluido. Los tres más nuevos se saltan la regla a propósito, y merece la pena explicar por qué en las dos direcciones.
Qué significa de verdad «sin motor»
En la práctica son tres cosas: un elemento <canvas>, un bucle movido por
requestAnimationFrame, y todas las formas de la pantalla dibujadas con código
en lugar de cargadas como imagen. No hay grafo de escena, ni sistema de
entidades y componentes, ni cadena de assets. Un sprite es una función que
recibe un contexto y unos números y llama a fillRect unas cuantas veces.
Suena primitivo porque lo es. También es la razón de que Reefhold cargue antes de que hayas terminado de leer su título.
Las tres cosas que acabas escribiendo tú
Un motor te las da gratis. Sin él, son los tres primeros ficheros que escribes, y son los mismos tres ficheros en todos los juegos:
- Un bucle de paso fijo.
requestAnimationFramete da un delta de tiempo real, no un tick. Si mueves las cosas directamente con ese delta, el juego se comporta distinto en un portátil a 60 Hz y en un monitor a 144 Hz, y una física que en las pruebas iba bien se vuelve rara ahí fuera. La solución es acumular tiempo real y avanzar la simulación en porciones fijas, dibujando una interpolación entre las dos últimas. - Una entrada que sea igual en táctil y en teclado. La mitad del tráfico
son móviles. Un juego que lee
keydowny nada más es injugable para esa gente, y uno que trata el táctil como caso especial en todas partes es el doble de código. El truco es normalizar las dos cosas en un pequeño objeto de «intención» (una dirección y un conjunto de acciones mantenidas) y que el resto del juego lea solo eso. - Un audio que sobreviva a la política de reproducción automática. Un
navegador no deja que suene nada hasta que el usuario ha interactuado con la
página. Si creas tu
AudioContextal cargar, nace suspendido y no se recupera nunca. Créalo en el primer evento de puntero o de tecla, y condiciona a eso todos los sonidos posteriores.
Eso son unas 150 líneas, compartidas tal cual entre los juegos que las usan.
Lo que da
- Un paquete que ningún portal cuestiona. Los portales curados tienen límites de tamaño estrictos y rechazan lo que se pasa sin posibilidad de recurso. Un juego de 63 KB no da pie a ninguna conversación.
- Una primera carga instantánea, que con datos móviles es la diferencia entre un jugador y alguien que se va.
- Nada que licenciar. Cuando alguien pide licenciar uno de estos juegos, no hay ninguna licencia de terceros que leerle, ningún fichero de atribuciones, ningún «bueno, depende de Phaser, y Phaser es MIT, pero».
Dónde está el límite
Scrapforge, ScaleSling y Husktide están hechos con Phaser, y fue la decisión correcta en los tres. Scrapforge y ScaleSling necesitan un solucionador de física de verdad, y un solucionador de restricciones 2D no es algo que merezca la pena volver a escribir mal. Husktide pone cientos de entidades en pantalla a la vez y se apoya en un atlas de texturas y en un renderizador afinado para conseguirlo.
Visto en retrospectiva, el patrón está bastante claro: el enfoque puro escala a juegos de colocación y timing (la mayoría de puzles, la mayoría de idles, la mayoría de arcades de puntuación). Deja de escalar en cuanto necesitas muchos cuerpos que interactúan o un modelo de física con esquinas. En ese punto el motor deja de ser un lastre y pasa a ser lo que mantiene el paquete más pequeño de lo que acabaría siendo la versión hecha a mano.
Los tamaños de cada juego están publicados en la página de licencias, si quieres las cifras reales.
