Por que eu devo ler este artigo:Neste artigo vamos focar na finalização do nosso jogo usando o Enchant.js, bem como na publicação do mesmo via Apache Cordova, efetuando todos os testes diretamente de um simulador Android, o Genymotion, e viabilizando a geração do arquivo de instalação apk para distribuição a nível de produção. Ao final deste, o leitor estará apto também a entender como detectar colisões entre objetos, implementar sons de fundo e de efeitos usando a API de áudio da HTML5, criar transições de tela entre menu, jogo e tela de game over, bem como gerar a impressão de personagens de forma aleatória usando somente os recursos do Enchant.js aliados aos seus plugins e interface de linha de comando.

Na primeira parte do curso iniciamos a implementação do nosso jogo “Fuga dos Dragões” com a inclusão do plano de fundo animado e do personagem principal (dragão) ao mesmo. Entendemos não só o que tange à configuração e instalação do Apache Cordova e do Enchant.js, mas também como ambos os frameworks se comportam em conjunto com conceitos como orientação a objetos, animação, canvas, bem como performance e superposição de imagens. Tais conceitos não só moldam o universo de games 2D na web como também definem novos fluxos de execução que serão totalmente regidos pela criatividade dos desenvolvedores e suas equipes.

Neste artigo iremos tratar de finalizar o jogo por completo, adicionando os personagens inimigos, os marcadores de pontuação e as transições de telas para quando o jogador for atingido e o jogo precisar exibir uma mensagem de Game Over com a opção de começar uma nova partida. Para essa implementação em especial, destaca-se o uso que faremos da API nativa do Cordova para salvar as informações referentes ao melhor resultado atingido pelo jogador naquele dispositivo em específico, dado este que poderá ser usado nas partidas futuras exibindo para o mesmo qual a sua melhor pontuação desde que começou a jogar.

Além disso, algumas definições são sempre menos vistas em tutoriais desse estilo, tais como a criação de menus, ou a definição de rotas que o jogador pode seguir atreladas a níveis de dificuldade que vão aumentando com o passar do tempo. Ao final faremos um tour pelos principais plugins disponíveis para o framework e você poderá ver que tipos de tecnologias podem ser acrescentadas ao seu projeto para ajudar a maximizar o poder de criação nos seus jogos.

Criando os inimigos

Após a implementação do dragão e toda a lógica envolvida em exibi-lo na horizontal e movimentá-lo na vertical, você já tem em mãos uma ligeira impressão de como esse código poderá ser reaproveitado para construir a lógica dos inimigos. Assim como para os demais objetos desenháveis que representamos no código anteriormente, o Inimigo também deverá ter a sua própria classe. Logo, para isso, adicione o código contido na Listagem 1 ao final do nosso arquivo main.js observando as semelhanças com o objeto Dragao, por exemplo, bem como as sobrescritas de métodos na herança estabelecida.

Listagem 1. Criando a classe de Inimigo e adicionando ao main.js.


  01  /**
  02  * Classe Inimigo
  03  */
  04 var Inimigo = Class.create(Sprite, {
  05     /**
  06      * O inimigo que o dragão deve evitar
  07      */
  08     initialize: function(faixa) {
  09         Sprite.apply(this,[48, 49]);
  10         this.image = Game.instance.assets['res/bola-fogo.png'];      
  11         this.rotationSpeed = 0;
  12         this.setFaixa(faixa);
  13         this.duracaoAnimacao = 0;
  14         this.addEventListener(Event.ENTER_FRAME, this.atualizar);
  15     },
  16 });

Antes de entendermos a listagem é preciso que saibamos como o código de pintura dos objetos de inimigo irá se comportar. A ideia é que dividamos a tela em três “faixas” horizontais que tomarão todo o espaço vertical da tela do jogo. Cada faixa terá um identificador e servirá para ações como definir onde o próximo objeto será impresso, bem como criar certas regras que impossibilitem mais de um objeto ser impresso na mesma faixa ao mesmo tempo. Após um objeto ser impresso, automaticamente setamos um tempo x que será contado para a impressão do objeto posterior e assim sucessivamente. Isso irá nos poupar o trabalho de ter de criar divisões verticais também para definir onde cada objeto deveria ser impresso sem que essa repetição ocorresse.

Perceba que logo no início do código estamos usando uma estrutura ainda não vista no artigo, a chamada ao método create() com a classe Sprite (do Enchant.js) passada como primeiro argumento. Isso por que a classe Inimigo será uma subclasse de Sprite e esta irá nos ajudar a definir as configurações de posicionamento dos objetos através do parâmetro faixa que recebemos no construtor do método initialize. Na linha 9 temos a aplicação das dimensões da imagem do inimigo. Perceba que estamos usando apenas a imagem da bola de fogo (linha 10), mas mais na frente configuraremos o jogo para lidar com mais personagens randomicamente. Em seguida, definimos a velocidade de rotação para zero (linha 11), uma vez que o personagem fará uma movimentação vertical retilínea e que necessariamente não poderá ter desvios. Após isso, configuramos a duração da animação inicialmente com zero também, mas esse dado será atualizado mais à frente. Note que esses tipos de configurações servem somente para declarar os nomes dos atributos que precisaremos nesse objeto, mesmo que seus valores estejam zerados.

Na linha 14 temos a adição do evento de ENTER que, na verdade, irá capturar o momento em que devemos atualizar o objeto, de fato. Note que ainda não implementamos duas outras funções que estão sendo usadas na função initialize: a função setFaixa() que definirá a posição do objeto de acordo com o seu número de faixa, e a função atualizar() que será chamada a cada novo frame impresso na tela.

Agora adicionemos o código relativo à primeira função das duas (Listagem 2).

Listagem 2. Adicionando a função setFaixa() à classe Inimigo.


  01 setFaixa: function(faixa) {
  02     var jogo, distancia;
  03     jogo = Game.instance;        
  04     distancia = 90;
  05 
  06     this.y = jogo.height / 2 - this.height / 2 + (faixa - 1) * distancia;
  07     this.x = ... 

Quer ler esse conteúdo completo? Tenha acesso completo