Criando o Roll-It

O Roll It é um experimento do Chrome que reinventa um clássico jogo de calçadão usando apenas o navegador do smartphone e do computador. O navegador do telefone permite que você aponte e role a bola com um movimento do pulso, enquanto o navegador do computador renderiza os gráficos em tempo real do Roll It Alley com WebGL e Canvas. Os dois dispositivos se comunicam por Websockets. Nenhum app. Nenhum download. Nenhum token. Você só precisa de um navegador moderno.

Com a direção do Google Creative Lab, a Legwork desenvolveu a experiência do usuário, as interfaces e o ambiente de jogos, depois se juntou ao parceiro de desenvolvimento Mode Set para criar o Roll It. Ao longo do projeto, houve uma série de desafios únicos. Este artigo explica algumas das técnicas que usamos, truques que descobrimos e lições que aprendemos para dar vida ao Roll It.

Fluxo de trabalho 3D

Uma das dificuldades no começo foi descobrir a melhor maneira de levar os modelos 3D do nosso software para um formato de arquivo pronto para a Web. Depois de criar os recursos dentro do Cinema 4D, os modelos foram simplificados e convertidos em malhas de poucos polígonos. Cada malha recebeu determinadas tags de seleção de polígono para diferenciar partes do objeto para colorir e texturizar. Conseguimos então exportar como um arquivo Collada 1.5 (.dae) e importar para o Blender, um programa 3D de código aberto, para criar arquivos compatíveis com o three.js. Depois de confirmar que os modelos foram importados corretamente, exportamos a malha como um arquivo JSON e aplicamos a iluminação usando código. Veja uma análise mais detalhada das etapas que seguimos:

Modele o objeto dentro de C4D. Confira se as normais da malha estão voltadas para fora.
Modelar o objeto dentro do C4D. Confira se as normais da malha estão voltadas para fora.
Usando a ferramenta de seleção de polígonos, crie tags de seleção das áreas específicas que você quer texturizar. Aplique materiais a cada uma das tags de seleção.
Com a ferramenta de seleção de polígonos, crie tags de seleção das áreas específicas que você quer texturizar. Aplique materiais a cada uma das tags de seleção.
Exporte a malha como um arquivo COLLADA 1.5 .dae.
Exporte a malha como um arquivo COLLADA 1.5 .dae.
Verifique se a opção "Exportar geometria 2D" está marcada. A exportação de triângulos costuma ser mais amplamente aceita em ambientes 3D no lado do código, mas tem a desvantagem de dobrar a contagem de polígonos. Quanto maior a contagem de polígonos, mais tributação será o modelo no processador do computador. Portanto, deixe essa opção marcada se o desempenho estiver lento.
Verifique se a opção "Exportar geometria 2D" está marcada. A exportação de triângulos costuma ser mais amplamente aceita em ambientes 3D no lado do código, mas tem a desvantagem de dobrar a contagem de polígonos. Quanto maior a contagem de polígonos, mais tributação será o modelo no processador do computador. Portanto, deixe essa opção marcada se o desempenho estiver lento.
Importe o arquivo Collada para o Blender.
Importe o arquivo Collada para o Blender.
Depois de importados para o liquidificador, você verá que os materiais e as tags de seleção também foram transferidos.
Depois de importados para o liquidificador, você vai notar que os materiais e as tags de seleção também foram transferidos.
Selecione o objeto e ajuste os materiais como preferir.
Selecione o objeto e ajuste os materiais dele como preferir.
Exporte o arquivo como three.js
Exporte o arquivo no formato three.js para compatibilidade com webGL.

Como escrever o código

O Roll It foi desenvolvido com bibliotecas de código aberto e é executado de forma nativa em navegadores modernos. Com tecnologias como WebGL e WebSockets, a Web está se aproximando de experiências multimídia e de jogos com qualidade de console. A facilidade e o conforto com os quais os desenvolvedores podem criar essas experiências tem sido saltado à medida que ferramentas mais modernas são disponibilizadas para o desenvolvimento de HTML.

Ambiente para desenvolvedores

A maior parte do código original do Roll It foi escrita com o CoffeeScript, uma linguagem limpa e concisa que transcompila o código para JavaScript bem formado e verificado. O CoffeeScript se destaca no desenvolvimento de OOP com seu ótimo modelo de herança e tratamento de escopo mais limpo. O CSS foi escrito com a estrutura SASS, que fornece ao desenvolvedor várias ferramentas excelentes para aprimorar e gerenciar as folhas de estilo de um projeto. A configuração desses sistemas no processo de build leva um pouco de tempo, mas definitivamente vale a pena, especialmente para um projeto maior como o Roll It. Configuramos um servidor Ruby on Rails para compilar automaticamente nossos recursos durante o desenvolvimento, de modo que todas as etapas de compilação se tornem transparentes.

Além de criar um ambiente de codificação simplificado e confortável, otimizamos manualmente os recursos para minimizar solicitações a fim de carregar o site mais rapidamente. Executamos todas as imagens por alguns programas de compactação: ImageOptim e ImageAlpha. Cada programa otimiza imagens da sua própria maneira — sem e com perda, respectivamente. Com a combinação certa de configurações, eles podem reduzir significativamente o tamanho dos arquivos de imagem. Isso não só economiza largura de banda ao carregar imagens externas, mas, depois de otimizadas, suas imagens serão convertidas em strings codificadas em base64 muito menores para incorporação inline em HTML, CSS e JavaScript. Com relação à codificação base64, também incorporamos nossos arquivos de fontes WOFF e SVG Open Sans diretamente no CSS usando essa técnica, o que resultou em um total de solicitações ainda menor.

A cena 3D habilitada para física

THREE.js é a biblioteca onipresente de JavaScript 3D para a Web. Ele aborda matemática 3D de baixo nível e otimizações WebGL baseadas em hardware que permitem que meros mortais criem com facilidade cenas 3D interativas, bem iluminadas e bonitas, sem precisar escrever sombreadores personalizados ou realizar transformações manuais de matrizes. Physijs é um wrapper específico para TRÊS.js para uma conhecida biblioteca de física C++ que foi traduzida para JavaScript. Aproveitamos essa biblioteca para simular a bola rolando, pulando e pulando em direção ao seu destino em 3D.

Desde o início, queríamos não apenas tornar a experiência física de rolar a bola realista, mas também garantir que os objetos no jogo parecessem reais. Isso exigiu muitas iterações de ajuste da gravidade geral da cena Physijs, a velocidade da bola no arremesso do jogador, a inclinação do salto na faixa e as propriedades de atrito e restituição (salto) da bola e dos materiais da faixa. A combinação de mais gravidade e velocidade resultou em uma experiência de jogo mais realista.

Como suavizar

A maioria das combinações modernas de cartão de vídeo e navegador deve aproveitar o anti-aliasing nativo baseado em hardware no ambiente WebGL, mas algumas não funcionam bem. Caso o anti-aliasing não funcione nativamente, quaisquer arestas duras e contrastantes na cena THREE.js serão irregulares e feias (pelo menos para os nossos olhos discernidos).

Felizmente, há uma correção: com um snippet de código, podemos detectar se a plataforma oferece suporte nativo ao antialias. Se for o caso, pronto. Se não, há uma série de sombreadores pós-processamento fornecidos com THREE.js que podem nos ajudar. ou seja, o filtro anti-aliasing FXAA. Ao redesenhar a cena renderizada a cada frame com esse sombreador, geralmente temos uma aparência muito mais suave para as linhas e bordas. Confira a demonstração abaixo:

// Check for native platform antialias support via the THREE renderer
// from: http://codeflow.org/entries/2013/feb/22/how-to-write-portable-webgl/#antialiasing
var nativeAntialiasSupport = (renderer.context.getParameter(renderer.context.SAMPLES) == 0) ? false : true;

Controles de jogo baseados em acelerômetro

Boa parte da magia do "Roll It" vem do gesto de rolar a bola que o jogador faz com o smartphone. Dispositivos móveis têm acesso ao acelerômetro no navegador já há algum tempo, mas como setor, estamos apenas começando a explorar o reconhecimento de gestos baseado em movimento na Web. Estamos um pouco limitados pelos dados que o acelerômetro do celular oferece, mas, com um pouco de criatividade, podemos criar algumas experiências incríveis.

A detecção do gesto "Jogar" principal começa com o rastreamento das 10 atualizações mais recentes do acelerômetro que vêm do evento deviceorientation da janela. Ao subtrair o valor de inclinação anterior do valor atual, armazenamos o delta de ângulo entre os eventos. Depois, ao somar constantemente os últimos 10 deltas angulares, podemos detectar a rotação contínua à medida que o smartphone se move pelo espaço. Quando o smartphone passa do limite de mudança do ângulo de varredura, acionamos uma rolagem. Então, ao encontrar o maior delta de inclinação nessa curva, podemos estimar a velocidade da bola. No Roll It, essa velocidade é normalizada usando carimbos de data/hora que são anexados a cada atualização do acelerômetro. Isso ajuda a suavizar a velocidade variável na qual as atualizações do acelerômetro são transmitidas para o navegador em diferentes dispositivos.

Comunicação de WebSockets

Quando o jogador rola a bola com o smartphone, uma mensagem é enviada do smartphone para o laptop, pedindo para ele lançar a bola. Essa mensagem "roll" é enviada por meio de um objeto de dados JSON por meio de uma conexão WebSocket entre as duas máquinas. Os dados JSON são pequenos e consistem principalmente em um tipo de mensagem, velocidade de lançamento e direção de mira.

{
  "type": "device:ball-thrown",
  "speed": 0.5,
  "aim": 0.1
}

Toda a comunicação entre o laptop e o smartphone acontece por pequenas mensagens JSON como essa. Toda vez que o jogo atualiza seu estado na área de trabalho, ou o usuário inclina ou toca em um botão no telefone, uma mensagem WebSocket é transmitida entre as máquinas. Para manter essa comunicação simples e fácil de gerenciar, as mensagens de WebSockets são transmitidas usando um único ponto de saída de qualquer navegador. Por outro lado, há um único ponto de entrada no navegador de recebimento, com um objeto WebSocket lidando com todas as mensagens recebidas e enviadas nas duas extremidades. Quando uma mensagem WebSocket é recebida, os dados JSON são retransmitidos no aplicativo JavaScript usando o método trigger() do jQuery. Nesse ponto, os dados recebidos se comportam como qualquer outro evento DOM personalizado e podem ser coletados e processados por qualquer outro objeto no aplicativo.

var websocket = new WebSocket(serverIPAddress);

// rebroadcast incoming WebSocket messages with a global event via jQuery
websocket.onmessage = function(e) {
  if (e.data) {
    var obj = JSON.parse(e.data);
    $(document).trigger(data.type, obj);
  }
};

// broadcast outgoing WebSocket messages by passing in a native .js object
var broadcast = function(obj) {
  websocket.send(JSON.stringify(obj));
};

Os servidores WebSocket do Roll It's são criados quando dois dispositivos são sincronizados com um código de jogo. O back-end do Roll It foi criado nas plataformas Google Compute Engine e App Engine usando Go.

Como inclinar telas do menu

Além das mensagens WebSocket orientadas a eventos usadas durante o jogo, os menus no Roll It são controlados inclinando o telefone e tocando em um botão para confirmar uma seleção. Isso exige um fluxo mais consistente de dados de inclinação da transmissão do celular para o laptop. Para reduzir a largura de banda e evitar o envio de atualizações desnecessárias, essas mensagens só serão enviadas se a inclinação do dispositivo mudar em mais de alguns graus. Não adianta enviar um fluxo de dados de inclinação se o smartphone estiver deitado em uma mesa. A taxa de transmissão também é limitada: não mais de 15 mensagens de WebSockets são enviadas por segundo no Roll It, mesmo que o dispositivo esteja inclinado de maneira ativa.

Depois que os valores de inclinação são captados no computador, eles são interpolados ao longo do tempo usando requestAnimationFrame para manter uma sensação suave. O resultado final é um menu giratório e uma bola que rola para ajudar a indicar a seleção do usuário. À medida que o smartphone envia dados de inclinação, esses elementos DOM são atualizados em tempo real recalculando uma transformação CSS dentro do loop requestAnimationFrame. O contêiner do menu simplesmente gira, mas a bola parece rolar no chão. Para conseguir esse efeito, implementamos alguma trigonometria básica para relacionar a coordenada x das bolas com a rotação dela. A equação simples é: rotações = x / (diâmetro * π)

Conclusão

Roll It é um sinal dos tempos. Entre os projetos de código aberto que impulsionaram seu desenvolvimento, o poder de processamento dos dispositivos em nossos escritórios e em nossos bolsos e o estado da Web como plataforma, é um momento verdadeiramente empolgante e transformador para estar conectado na Web aberta. Há apenas alguns anos, grande parte dessa tecnologia só existia em sistemas reservados, indisponíveis para uso e distribuição livres. Hoje, experiências complexas podem ser realizadas com menos trabalho e mais imaginação enquanto criamos e compartilhamos novas peças do quebra-cabeça todos os dias. O que você está esperando? Construa algo incrível e compartilhe com o mundo!

Logotipo da Roll it