Dezembro 2015

Volume 30 – Número 13

Desenvolvimento de jogos – Babylon.js: Construindo um jogo básico para a Web

Por Raanan Weber

O Babylon.js é um mecanismo 3D baseado em WebGL focado principalmente em desenvolvimento de jogos e facilidade de uso. Como um mecanismo 3D, ele possui ferramentas para criar, exibir e texturizar malhas no espaço, assim como adicionar fontes de luz e câmeras. Por ser focado em jogos, o Babylon.js possui algumas funcionalidades adicionais que um mecanismo 3D normal não requer. Ele conta com suporte nativo para detecção de colisão, gravidade de cenário, câmeras orientadas para jogos (por exemplo, câmeras de acompanhamento que rastreiam objetos em movimento), assim como suporte nativo para Oculus Rift e outros dispositivos de realidade virtual (VR). Ele possui um sistema de plug-in de mecanismo de física, suporte de áudio nativo, um gerenciador de ações baseado em entrada e muito mais. Explorarei todas essas funcionalidades neste tutorial.

Sobre o tutorial

Neste tutorial, desenvolverei um jogo simples de boliche. Criarei a pista de boliche, adicionarei 10 pinos e uma bola de boliche, assim como o recurso para jogar a bola. Meu jogo com certeza não ficará pronto para ser lançado, mas mostrará como você pode desenvolver um jogo usando as ferramentas fornecidas pelo Babylon.js. Evitarei usar, de propósito, quaisquer ferramentas durante o desenvolvimento. Os objetos, câmeras, texturas e outros recursos serão criados usando somente código JavaScript.

A versão do Babylon.js usada durante este tutorial é a última versão estável – a 2.1. David Catuhe e a equipe de desenvolvimento do Babylon estão tentando manter a estrutura o mais compatível possível com versões anteriores, por isso, acho que este tutorial funcionará adequadamente em versões futuras, pelo menos até a próxima grande versão. Eu estou usando o Visual Studio 2015 Community Edition, mas você pode usar qualquer IDE que quiser.

O tutorial será dividido em duas partes. Neste artigo, apresentarei uma visão geral dos blocos de construção básicos do Babylon.js. Criarei as malhas, a textura delas, adicionarei câmeras e fontes de luz, assim como ativarei uma interação de usuário simples. Na segunda parte, mostrarei os pontos fortes do Babylon.js adicionando colisão e física, áudio, ações de usuário e tipos especiais de câmeras.

Introdução: Um novo projeto Babylon.js

Um projeto Babylon.js simples é um site estático. Como estou usando o Visual Studio, usarei o servidor IIS local incorporado no Visual Studio para hospedar esses arquivos estáticos. O Visual Studio não tem um modelo para site estático, por isso, é necessário uma abordagem diferente.

Primeiro, crie uma nova solução em branco. Abra o Visual Studio e vá para Arquivo | Novo | Projeto. Selecione Outros Tipos de Projetos no painel esquerdo e, em seguida, Solução em branco, como mostrado na Figura 1. Atribua um nome à solução (Eu usei BabylonBowling) e clique em OK.

Criação de uma nova Solução em branco no Visual Studio
Figura 1 - Criação de uma nova Solução em branco no Visual Studio

Para criar um nov site estático, primeiro você precisa criar um novo diretório para hospedá-lo. Clique com o botão direito do mouse para esvaziar a solução, em seguida, clique em Abrir pasta no Gerenciador de Arquivos, como mostrado na Figura 2.

Abrindo a pasta da solução no Gerenciador de Arquivos
Figura 2 - Abrindo a pasta da solução no Gerenciador de Arquivos

Crie um novo diretório para o projeto chamado BabylonBowling e feche o Gerenciador de Arquivos.

Clique com o botão direito do mouse na solução e escolha Adicionar | Site Existente. Selecione a pasta criada recentemente (certifique-se de escolher a pasta que acabou de criar e não a pasta da solução) e clique em Abrir. Agora, você deve ter um site em branco como o único projeto desta solução.

Após criar o projeto, você precisa adicionar a estrutura e as dependências da estrutura. Há algumas formas de fazer isso. A maneira mais simples é usar o Gerenciador de Pacote NuGet.

Clique com o botão direito do mouse no projeto e escolha Gerenciar pacotes NuGet. Clique no campo de pesquisa (o atalho do teclado é Ctrl+E) e digite babylon. Você verá uma janela parecida com a da Figura 3. Selecione BabylonJS. Confirme se a versão selecionada é a 2.1 (ou a última versão estável) e clique em Instalar. Clique em OK na janela de visualização que aparece (se aparecer uma) e o Babylon.js será instalado em seu projeto vazio, incluindo a cena de demonstração.

Adicionar o Babylon.js usando o Gerenciador de Pacote NuGet
Figura 3 - Adicionar o Babylon.js usando o Gerenciador de Pacote NuGet

Para os que usam npm como gerenciador de pacote, você pode instalar o Babylon.js usando o comando:

npm install babylonjs

Depois de instalar o pacote, você deve ter os seguintes arquivos na pasta de scripts:

  • babylon.js, uma versão minificada do Babylon.js
  • babylon.max, uma versão depurada do Babylon.js
  • Oimo.js é o mecanismo de física Oimo JS que será usado na segunda parte deste tutorial
  • poly2tri.js, é uma biblioteca de triangulação opcional (github.com/r3mi/poly2tri.js)
  • hand-minified.js, um polyfill de eventos de ponteiros; em falta quando estiver usando o npm, por isso, instale usando o comando:
npm install handjs

O instalador NuGet também cria um arquivo index.html e um arquivo index.js.

Um erro no pacote NuGet adiciona uma linha desnecessária ao web.config. Até estar resolvido, clique duas vezes neste arquivo e remova a linha realçada na Figura 4 (na minha solução, é a linha 9).

Exclua a linha realçada do web.config
Figura 4 - Exclua a linha realçada do web.config

Agora você já pode testar o projeto. Abra o projeto em seu navegador padrão usando Ctrl+Shift+W ou clicando no botão Executar na parte superior da barra de navegação. Se você vir a nave espacial em 3D mostrada na Figura 5, seu projeto está pronto.

Nave espacial padrão do Babylon
Figura 5 - Nave espacial padrão do Babylon

Para aqueles que estiverem usando IDEs diferentes, basta seguir o tutorial “Como criar uma cena básica” na página de documentação do Babylon.js para chegar ao estado atual. Eu ainda recomendo usar o npm para instalar as dependências se não estiver usando o NuGet. O tutorial pode ser encontrado em bit.ly/1MXT6WP.

Para começar do zero, exclua a função createScene no index.js.

Os blocos de construção

Os primeiros dois elementos que vou discutir são o mecanismo e a cena.

O mecanismo é o objeto responsável pela comunicação com o API WebGL de nível baixo (o WebGL 1 é baseado no OpenGL ES2, com uma sintaxe muito parecida). Em vez de forçar você a escrever um código WebGL de nível baixo, o mecanismo fornece uma API de nível alto e mais fácil de entender. Ela também é transparente para o desenvolvedor. Exceto na configuração inicial do projeto, eu não vou usar diretamente o mecanismo de forma alguma. Algumas funcionalidades de nível baixo podem ser conseguidas usando o mecanismo, mas eu não vou abordar esta parte.

O mecanismo requer dois parâmetros para inicializar. O primeiro é uma tela para desenhar. A tela é um elemento HTML já incluída no index.html. O segundo parâmetro é o estado de suavização (ligado ou desligado).

Abra o index.js atual em branco e adicione as seguintes linhas de código:

function init() {
  var engine = initEngine();
}
function initEngine() {
  // Get the canvas element from index.html
  var canvas = document.getElementById("renderCanvas");
  // Initialize the BABYLON 3D engine
  var engine = new BABYLON.Engine(canvas, true);
  return engine;
}

Durante o desenvolvimento, vou usar a função init para adicionar uma nova funcionalidade em cada etapa. Cada elemento que eu crio terá sua própria função.

Para entender o que a cena representa, imagine um site com suas diferentes páginas. Uma página da Web contém texto, imagens, ouvintes de eventos e todos os outros recursos necessários para renderizar essa única página. Carregar uma página diferente carrega recursos diferentes.

Apenas como uma única página Web, a cena possui os recursos necessários para mostrar uma única “página” 3D. Esta cena pode ser muito grande e cheia de recursos – malhas, câmeras, luzes, ações do usuário e muito mais. Porém, para mover de uma página para outra, é recomendado uma nova cena. A cena também é responsável por renderizar seus próprios recursos e comunicar as informações necessárias para o mecanismo. O jogo de boliche exige apenas uma única cena. Mas se planejar adicionar níveis novos ou um jogo bônus, tenho de criá-los usando novas cenas.

Para inicializar, a cena requer apenas o mecanismo que eu criei. Adicione ao index.js o seguinte:

function createScene(engine) {
  var scene = new BABYLON.Scene(engine);
  // Register a render loop to repeatedly render the scene
  engine.runRenderLoop(function () {
      scene.render();
  });
}

Primeiro, eu crio o objeto da cena. As próximas linhas são a única interação que eu terei com o mecanismo. Eles informam ao mecanismo para renderizar esta cena específica toda vez que o loop do renderizador estiver em execução.

Adiciono esta linha de código ao fim da função init para criar realmente a cena:

var scene = createScene(engine);

Só mais duas coisas antes de continuar. Ao dimensionar a janela do navegador, a tela também está sendo redimensionada. O mecanismo também deve redimensionar sua largura e altura internas para manter a cena em perspectiva. Adicione as seguintes linhas à função initEngine pouco antes do mecanismo de retorno, assim, a instrução manterá a cena em perspectiva:

// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
  engine.resize();
});

A segunda coisa é alterar o index.html para usar a nova função init. Abra o index.html e encontre a marcação do script contendo a chamada para o createScene. Altere o createScene para init, em seguida, salve o index.html e feche-o.

A cena tem uma camada de depuração extremamente avançada que permite que você depure a cena sendo renderizada. Ela mostra o número de malhas sendo renderizadas e os quadros atuais por segundo (FPS). Isto permite desligar recursos como texturização e sombras e torna fácil encontrar malhas perdidas. Ligar a camada de depuração é simples:

scene.debugLayer.show();

Faça isso e você será capaz de depurar sua cena sozinho.

Agora tenho um mecanismo e uma cena, e estou pronto para começar a adicionar uma câmera, luzes e malhas para criar minha cena de pista de boliche.

Câmeras

O Babylon.js oferece muitos tipos de câmeras, cada uma com seus próprios objetivos específicos. Antes de escolher a câmera para o jogo, vamos analisar os tipos mais comuns:

  • A Free Camera é uma câmera de tiro em primeira pessoa. Ela pode se mover livremente ao longo da cena, usando as setas do teclado, e a direção pode ser ajustada usando o mouse. A gravidade opcional e a detecção de colisão também podem ser ativadas.
  • A Arc Rotate Camera é usada para girar em torno de um alvo específico. Usando o mouse, o teclado ou os eventos de toque, o usuário pode ver o objeto de todas as direções.
  • A Touch Camera é uma câmera livre que usa eventos de toque como entrada. Ela é adequada para todas as plataformas móveis.
  • A Follow Camera segue automaticamente um alvo específico.

O Babylon.js suporta WebVR e câmeras de orientação de dispositivo de forma nativa, o que significa que você pode lidar com dispositivos deste tipo como o Oculus Rift ou o Google Cardboard.

Um novo conceito introduzido na versão 2.1 torna cada tipo de câmera preparado para 3D. Isso significa que cada tipo de câmera pode ser ajustado para se adaptar a uma visão estereoscópica do estilo do Oculus Rift e a óculos vermelhos e azuis (3D anaglífico). A Figura 6 mostra a cena da nave espacial renderizada com a câmera sem anaglifo e a Figura 7 mostra a cena com a câmera estereoscópica.

Câmera 3D anaglífica
Figura 6 - Câmera 3D anaglífica

Câmera estereoscópica
Figura 7 - Câmera estereoscópica

Para o meu jogo de boliche, usarei dois tipos de câmeras. A primeira é a câmera principal do jogador, que ajustará a posição a partir da qual a bola de boliche será arremessada. Este é o objetivo exato da câmera livre. Também quero adicionar uma visão diferente – quando a bola está em rota, eu quero acompanhá-la até ela atingir os pinos.

Primeiro, eu adiciono a câmera livre. A função createFreeCamera usa a cena como uma variável única:

function createFreeCamera(scene) {
  var camera = new BABYLON.FreeCamera(
    "player camera", BABYLON.Vector3.Zero(), scene);
  return camera;
}

Eu criei a posição da câmera na localização 0,0,0 da minha cena. Mais tarde, ampliarei esta função (quando necessário) para configurar ainda mais a câmera.

E, é claro, sem esquecer de adicioná-la à função init no fim:

...
// Create the main player camera
var camera = createFreeCamera(scene);
// Attach the control from the canvas' user input
camera.attachControl(engine.getRenderingCanvas());
// Set the camera to be the main active camera
scene.activeCamera = camera;

A função attachControl registra os ouvintes de eventos necessários para a câmera específica (como aquelas para a entrada de mouse, touch ou teclado). Configurar a câmera ativa da cena informa à cena que esta câmera deveria ser usada para renderização.

Adicionarei a segunda câmera na parte dois, depois de ativar o arremesso de bola.

Criando a pista

Uma pista de boliche é uma estrutura geométrica relativamente simples. Começarei configurando algumas constantes, com as dimensões reais de uma pista de boliche em metros. A razão pela qual optei por metros está no mecanismo de física, que será explicado na segunda parte deste artigo.

Você pode ver as constantes no arquivo do projeto. Para calcular esses valores eu usei informações disponíveis online acerca de pistas de boliche.

Depois de configurar as constantes, estou pronto para criar as malhas que construirão a pista de boliche. Meu plano (2D) é mostrado na Figura 8. Começarei criando as malhas. A texturização das malhas, ou seja, atribuir materiais a elas, será realizada posteriormente.

Plano 2D da cena da pista de boliche
Figura 8 - Plano 2D da cena da pista de boliche

Primeiro, criarei um piso geral para a cena:

function createFloor(scene) {
  var floor = BABYLON.Mesh.CreateGround("floor", 100, 100, 1, scene, false);
  return floor;
}

Isso cria um piso simples de 100x100 metros. Todas as malhas criadas usando as funções internas do Babylon.js são criadas na posição 0,0,0 da cena e são centralizadas. Existem três variáveis importantes que transformam a malha e a posicionam corretamente na cena:

  • mesh.position é um vetor da posição da malha no espaço
  • mesh.scaling é o fator de escala da malha em cada um dos eixos
  • mesh.rotation são os ângulos Euler (em radianos) da rotação em cada eixo; se você se sente mais à vontade com os quatérnions (eu me sinto), você pode usar o mesh.rotationQuaternion em substituição

Depois de adicionar a função à minha função init e iniciar a cena, percebi uma coisa interessante – eu não consigo ver de forma alguma o piso que eu adicionei! O motivo é que a câmera e o piso foram ambos criados no mesmo ponto no espaço (0,0,0). Como o chão é completamente plano, ele só é visto na tela olhando de cima (ou de baixo). Voltando para a inicialização da câmera na função createCamera, eu mudei a segunda variável, que é a posição inicial da câmera, para um novo vetor – a câmera estará agora a 1.7 unidades (metros, neste caso) acima do chão:

var camera = new BABYLON.FreeCamera(
  "cam", new BABYLON.Vector3(0,1.7,0), scene);

Se você iniciar a cena agora, verá o piso se alongando até a metade da tela, como mostrado na Figura 9.

Adicionando um piso à cena
Figura 9 - Adicionando um piso à cena

Experimente se mover com as setas e o mouse para pegar o jeito do controle da câmera livre.

Você perceberá que o piso está totalmente preto. Falta luz! Adicionarei uma nova função, createLight, que ampliarei mais tarde.

function createLight(scene) {
  var light = new BABYLON.DirectionalLight(
    "dir01", new BABYLON.Vector3(-0.5, -1, -0.5), scene);
  // Set a position in order to enable shadows later
  light.position = new BABYLON.Vector3(20, 40, 20);
  return light;
}

Não se esqueça de adicionar esta linha ao init:

var light = createLight(scene);

O Babylon.js tem quatro tipos de luz:

  • Hemisférico: Luz ambiente, predefinida com cor de fundo (os pixels virados para baixo), cor do céu (os pixels virados para cima) e cor especular.
  • Ponto: Uma luz emitida de um único ponto de luz em todas as direções, como o sol.
  • Ponto de luz: Como o nome sugere, uma luz vinda de um único ponto com uma direção e um raio de emissão específicos. Esta luz pode criar sombras.
  • Direcional: Luz emitida em uma direção específica a partir de qualquer lugar. O sol pode ser uma luz pontual, mas uma luz direcional simula melhor a luz do sol. Esta luz também pode criar sombras e é a que eu estou usando em meu exemplo.

Agora o piso ficará branco. O Babylon.js atribui um material branco padrão a cada malha sem material atribuído.

A pista em si será uma caixa, deitada no piso que eu acabei de criar.

function createLane(scene) {
  var lane = BABYLON.Mesh.CreateBox("lane", 1, scene, false);
  lane.scaling = new BABYLON.Vector3(
    laneWidth, laneHeight, totalLaneLength);
  lane.position.y = laneHeight / 2; // New position due to mesh centering
  lane.position.z = totalLaneLength / 2;
  return lane;
}

Mais uma vez, não se esqueça de adicionar esta função ao init.

Você pode ver como eu usei o parâmetro de colocação em escala – eu criei uma caixa com o tamanho de 1x1x1 e mudei sua colocação em escala para se ajustar às constantes que eu predefini.

Usando a mesma técnica, eu criei duas caixas que atuarão como minhas bordas da vala nos dois lados da pista (que é para onde a bola cairá quando for arremessada na direção errada). Experimente criá-las você mesmo, depois confira o projeto de acompanhamento para ver como é que eu fiz.

Pinos e bola de boliche

Agora só faltam os pinos e a bola de boliche. Para criar os pinos, usarei um cilindro, somente um cilindro que será multiplicado muitas vezes – 10 para ser exato. No Babylon.js, estas multiplicações são chamadas de instâncias. Uma instância é uma cópia exata de uma malha, exceto para sua transformação no espaço. Isso significa que a geometria e a textura de uma instância não podem ser mudadas, mas a posição, a colocação em escala e a rotação podem. Eu pessoalmente nunca uso o objeto original na cena; se eu quiser 10 pinos, eu crio um pino, desativo-o e crio 10 instâncias dele em 10 locais predefinidos:

function createPins(scene) {
  // Create the main pin
  var mainPin = BABYLON.Mesh.CreateCylinder(
    "pin", pinHeight, pinDiameter / 2, pinDiameter, 6, 1, scene);
  // Disable it so it won't show
  mainPin.setEnabled(false);
  return pinPositions.map(function (positionInSpace, idx) {
    var pin = new BABYLON.InstancedMesh("pin-" + idx, mainPin);
    pin.position = positionInSpace;
    return pin;
  });
}

As variáveis em falta usadas nesta função podem ser encontradas no arquivo do projeto, incluindo a pinPositions, que é uma matriz com as posições globais dos 10 pinos.

Agora para a bola de boliche. A bola de boliche é uma esfera simples, com 3 furos para os dedos. Para criar a esfera, usarei a função CreateSphere oferecida pelo Babylon.js:

var sphere = BABYLON.Mesh.CreateSphere("sphere", 12, 0.22, scene);

Agora eu preciso fazer os furos. Para isso, usarei uma funcionalidade chamada geometria sólida construtiva (CSG) integrada no Babylon.js, que permite adicionar ou subtrair malhas de malhas existentes, ou melhor ainda, adicionar ou subtrair geometrias umas das outras. Isso significa que se duas malhas se interseccionarem, eu posso “remover” uma da outra e obter uma malha alterada. No meu caso, eu quero criar três furos redondos na esfera. Um cilindro encaixará perfeitamente.

Primeiro, eu crio o cilindro que usarei para o primeiro furo:

var cylinder = BABYLON.Mesh.CreateCylinder(
  "cylinder", 0.15, 0.02, 0.02, 8, 1, scene, false);

Em seguida, mudarei a posição do cilindro para interseccionar com a esfera:

cylinder.position.y += 0.15;

Então, criarei os objetos CSG e os usarei para subtrair o cilindro da esfera:

var sphereCSG = BABYLON.CSG.FromMesh(sphere);
var cylinderCSG = BABYLON.CSG.FromMesh(cylinder);
sphereCSG.subtractInPlace(cylinderCSG);
var ball = sphereCSG.toMesh("test", sphere.material, scene, false);

A Figura 10 mostra como ficam a esfera e os cilindros, e logo ao lado a bola de boliche que foi criada usando o CSG.

Criando a bola de boliche
Figura 10 - Criando a bola de boliche

A Figura 11 e o playground em babylonjs-playground.com/#BIG0J mostram todo o código usado para criar a bola do zero.

Figura 11 - Criando uma bola de boliche usando CSG

// The original sphere, from which the ball will be made
var sphere = BABYLON.Mesh.CreateSphere("sphere", 10.0, 10.0, scene);
sphere.material = new BABYLON.StandardMaterial("sphereMat", scene);
// Create pivot-parent-boxes to rotate the cylinders correctly
var box1 = BABYLON.Mesh.CreateBox("parentBox", 1, scene);
var box2 = box1.clone("parentBox");
var box3 = box1.clone("parentBox");
// Set rotation to each parent box
box2.rotate(BABYLON.Axis.X, 0.3);
box3.rotate(BABYLON.Axis.Z, 0.3);
box1.rotate(new BABYLON.Vector3(0.5, 0, 0.5), -0.2);
[box1, box2, box3].forEach(function (boxMesh) {
// Compute the world matrix so the CSG will get the rotation correctly
  boxMesh.computeWorldMatrix(true);
  // Make the boxes invisible
  boxMesh.isVisible = false;
});
// Create the 3 cylinders
var cylinder1 = BABYLON.Mesh.CreateCylinder(
  "cylinder", 4, 1, 1, 30, 1, scene, false);
cylinder1.position.y += 4;
cylinder1.parent = box1;
var cylinder2 = cylinder1.clone("cylinder", box2);
var cylinder3 = cylinder1.clone("cylinder", box3);
// Create the sphere's CSG object
var sphereCSG = BABYLON.CSG.FromMesh(sphere);
// Subtract all cylinders from the sphere's CSG object
[cylinder1, cylinder2, cylinder3].forEach(function (cylinderMesh) {
  sphereCSG.subtractInPlace(BABYLON.CSG.FromMesh(cylinderMesh));
});
// Create a new mesh from the sphere CSG
var ball = sphereCSG.toMesh("bowling ball", sphere.material, scene, false);

Texturas

Todas as malhas que eu criei têm o material branco padrão. Para tornar a cena mais atraente, eu deveria adicionar outros materiais. O material padrão do Babylon.js (o sombreador padrão) tem muitas definições a serem exploradas, mas não as discutirei aqui. (Para saber mais sobre o sombreador padrão do Babylon.js você pode experimentar o BabylonJS Material Editor em materialeditor.raananweber.com.) No entanto, eu discutirei como eu texturizei a pista e a bola de boliche.

Para texturizar a bola de boliche eu usarei outra fantástica funcionalidade do Babylon.js – as texturas processuais. As texturas processuais não são texturas padrão que usam imagens 2D. Elas são texturas criadas programaticamente, geradas pelo GPU (em vez do CPU), que tem um impacto positivo de desempenho na cena. O Babylon tem muitos tipos de texturas processuais – madeira, tijolos, fogo, nuvens, grama e muito mais. Eu vou usar a textura pérola.

Depois de criar a malha da bola, vou adicionar a cor verde perolada (Figura 12) inserindo as seguintes linhas:

var marbleMaterial = new BABYLON.StandardMaterial("ball", scene);
var marbleTexture = new BABYLON.MarbleProceduralTexture(
  "marble", 512, scene);
marbleTexture.numberOfTilesHeight = 2;
marbleTexture.numberOfTilesWidth = 2;
marbleMaterial.ambientTexture = marbleTexture;
// Set the diffuse color to the wanted ball's color (green)
marbleMaterial.diffuseColor = BABYLON.Color3.Green();
ball.material = marbleMaterial;

Textura perolada aplicada na bola
Figura 12 - Textura perolada aplicada na bola

É possível adicionar uma textura de madeira à pista usando a textura difusa do material padrão. Mas não é só por isso que eu quis falar sobre o material da pista. Se você olhar para uma pista de boliche real, perceberá que ela tem diferentes conjuntos de pontos e um conjunto de flechas ou triângulos sobre ela. Para simular isso, eu poderia criar uma textura muito grande com todos esses detalhes, mas isso poderia prejudicar o desempenho (devido a uma textura muito grande) ou reduzir a qualidade da imagem.

Eu também poderia usar decalques, uma nova funcionalidade introduzida no Babylon.js 2.1. Os decalques são uma maneira de “desenhar” por cima de uma malha já texturizada. Eles podem ser usados, por exemplo, para simular tiros de bala em uma parede ou, como no meu caso, adicionar decorações a uma pista de boliche. Decalques são malhas e, por isso, são texturizadas usando materiais padrão. A Figura 13 mostra como eu adicionei a linha de falta e a Figura 14 mostra a aparência da pista depois de adicionar os decalques, assim como a aparência do piso e das calhas depois de usar texturas processuais (tijolos e grama) como materiais.

Figura 13 - Adicionando o decalque da linha de falta

// Set the decal's position
var foulLinePosition = new BABYLON.Vector3(0, laneHeight, foulLaneDistance);
var decalSize = new BABYLON.Vector3(1,1,1);
// Create the decal (name, the mesh to add it to, position, up vector and the size)
var foulLine = BABYLON.Mesh.CreateDecal("foulLine", lane, foulLinePosition, BABYLON.Vector3.Up(), decalSize);
// Set the rendering group so it will render after the lane
foulLine.renderingGroupId = 1;
// Set the material
var foulMaterial = new BABYLON.StandardMaterial("foulMat", scene);
foulMaterial.diffuseTexture =
  new BABYLON.Texture("Assets/dots2-w-line.png", scene);
foulMaterial.diffuseTexture.hasAlpha = true;
foulLine.material = foulMaterial;
// If the action manager wasn't initialized, create a new one
scene.actionManager = new BABYLON.ActionManager(scene);
// Register an action to generate a new color each time I press "c"
scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction({
  trigger: BABYLON.ActionManager.OnKeyUpTrigger, parameter: "c" },
  // The function to execute every time "c" is pressed"
  function () {
    ball.material.diffuseColor =
      new BABYLON.Color3(Math.random(), Math.random(), Math.random());
  }
));

Pista com decalques adicionada
Figura 14 - Pista com decalques adicionada

Entrada do usuário – o gerenciador de ações do Babylon.js

Como um mecanismo de jogos com todos os recursos, o Babylon.js tem uma maneira simples de interagir com a entrada do usuário. Digamos que eu queira mudar a cor da bola usando a tecla C. Sempre que eu pressionar C, eu quero definir uma cor aleatória à bola:

// If the action manager wasn't initialized, create a new one
scene.actionManager = new BABYLON.ActionManager(scene);
// Register an action to generate a new color each time I press C
scene.actionManager.registerAction(
  new BABYLON.ExecuteCodeAction({ trigger:
  BABYLON.ActionManager.OnKeyUpTrigger, parameter: "c" },
  // The function to execute every time C is pressed
  function () {
    ball.material.diffuseColor =
      new BABYLON.Color3(Math.random(), Math.random(), Math.random());
  }
));

O gerenciador de ações do Babylon.js é uma ferramenta poderosa para controlar ações de acordo com acionadores. Um acionador pode ser um movimento do mouse ou cliques, intersecções de malha ou uma entrada do teclado. Existem muitos acionadores e ações à escolha. Dê uma olhada no site do tutorial do Babylon.js (bit.ly/1MEkNRo) para ver todos eles.

Eu vou usar o gerenciador de ações para controlar a bola e reiniciar a cena. Adicionarei essas ações na segunda parte do tutorial.

Usando recursos externos.

Eu criei as malhas de que eu precisava usando as funções internas do Babylon.js. Na maioria das vezes, isso não será suficiente. O Babylon.js oferece muitas malhas, de esferas e caixas a faixas complexas, mas é difícil criar modelos complexos como pessoas, armas para criar um Doom para a Web ou uma nave espacial para seu clone do Space Invaders.

O Babylon.js oferece plug-ins de exportação para muitas ferramentas 3D conhecidas, como o Blender e o 3D-Studio. Você também pode exportar seus modelos do fantástico Clara.io e baixar um arquivo .babylon.

O Babylon.js usa seu próprio formato de arquivo que pode conter uma cena inteira, incluindo malhas, câmeras, luzes, animações, geometrias e outras informações. Por isso, se desejar, você pode usar o Blender somente para modelar toda a sua cena. Você também pode importar malhas individuais.

No entanto, isso não faz parte do escopo deste tutorial. Neste artigo, eu só queria mostrar como você pode criar um jogo simples usando só o Babylon.js

O que vem a seguir?

Eu pulei muitas funcionalidades integradas no Babylon.js. Ele tem uma quantidade enorme de funcionalidades e eu recomendo que você dê uma olhada no playground (babylonjs-playground.com), na página de documentação (doc.babylonjs.com), e na página do Babylon.js (babylonjs.com) para ver suas inúmeras possibilidades. Se você tiver dificuldade com qualquer parte deste tutorial, entre em contato comigo ou com qualquer um dos heróis do Babylon.js no fórum extremamente ativo de desenvolvedores de jogos do Babylon.js HTML5 (bit.ly/1GmUyzq).

No próximo artigo, criarei o jogo real – adicionando física e detecção de colisão, o recurso para jogar a bola, sons e muito mais.


Raanan Weberé consultor de TI, desenvolvedor de pilha completo, marido e pai. Em seu tempo livre, ele contribui para o Babylon.js e outros projetos de software livre. Você pode ler seu blog em blog.raananweber.com.

Agradecemos ao seguinte especialista técnico da Microsoft pela revisão deste artigo: David Catuhe