Pular para os jogos
Hadukis

Blog

Fazendo um jogo HTML5 sem engine e sem framework

· 3 min de leitura

Seis dos nove primeiros jogos da nossa página de jogos são lançados sem dependência de nenhum tipo: não usam engine, framework nem biblioteca em tempo de build. O menor, Reefhold, tem 63 KB em disco: o jogo inteiro, arte incluída. Os três mais novos quebram a regra de propósito, e vale explicar o porquê nas duas direções.

O que "sem engine" quer dizer na prática

Na prática, são três coisas: um elemento <canvas>, um loop movido por requestAnimationFrame, e cada forma na tela desenhada por código em vez de carregada como imagem. Não há scene graph, nem entity-component system, nem pipeline de assets. Um sprite é uma função que recebe um contexto e alguns números e chama fillRect algumas vezes.

Parece primitivo porque é. E também é o motivo de o Reefhold carregar antes de você terminar de ler o título.

As três coisas que você acaba escrevendo sozinho

Um engine te entrega isto de graça. Sem um, estes são os três primeiros arquivos que você escreve, e são os mesmos três arquivos em todo jogo:

  • Um loop de timestep fixo. O requestAnimationFrame te dá um delta de tempo real, não um tick. Se você move as coisas usando esse delta diretamente, o jogo roda diferente num notebook de 60 Hz e num monitor de 144 Hz, e uma física que parecia certa nos testes fica estranha no mundo real. A solução é acumular o tempo real e avançar a simulação em fatias fixas, renderizando uma interpolação entre as duas últimas.
  • Uma entrada que seja igual no toque e no teclado. Metade do tráfego é celular. Um jogo que lê keydown e mais nada é injogável para essas pessoas, e um que trata o toque como caso especial em todo lugar tem o dobro de código. O truque é normalizar os dois num pequeno objeto de "intenção" (uma direção e um conjunto de ações pressionadas) e deixar o resto do jogo ler só isso.
  • Um áudio que sobreviva à política de autoplay. O navegador não deixa um som tocar até o usuário interagir com a página. Se você cria o seu AudioContext no carregamento, ele começa suspenso e nunca se recupera. Crie-o no primeiro evento de ponteiro ou de tecla, e condicione todo som posterior a isso.

São umas 150 linhas, compartilhadas sem alteração entre os jogos que as usam.

O que isso compra

  • Um pacote que nenhum portal questiona. Os portais curados têm limites de tamanho rígidos e rejeitam o que passa deles, sem recurso. Um jogo de 63 KB nem entra em discussão.
  • Um primeiro carregamento instantâneo, o que no 4G é a diferença entre um jogador e alguém que vai embora.
  • Nada para licenciar. Quando alguém pede para licenciar um desses jogos, não há licença de terceiros para mostrar, nem arquivo de atribuição, nem "bom, depende do Phaser, e o Phaser é MIT, mas".

Onde fica o limite

Scrapforge, ScaleSling e Husktide são feitos em Phaser, e essa foi a decisão certa para os três. Scrapforge e ScaleSling precisam de um solver de física de verdade, e um solver de restrições 2D não é algo que valha a pena escrever de novo, e mal. Husktide põe centenas de entidades na tela ao mesmo tempo e depende de um atlas de texturas e de um renderizador ajustado para isso.

Olhando para trás, o padrão é bem claro: a abordagem pura escala para jogos sobre posicionamento e timing (a maioria dos puzzles, a maioria dos idle, a maioria dos arcades de pontuação). Ela para de escalar no momento em que você precisa de muitos corpos interagindo ou de um modelo de física cheio de casos difíceis. A partir daí, um engine não é sobrecarga: é o que mantém o pacote menor do que a versão feita à mão acabaria ficando.

Os tamanhos de cada jogo estão todos publicados na página de licenciamento, se você quiser os números exatos.