sexta-feira, 28 de junho de 2019

Aula 10 - animação sonic com teclado

sonic.html

<!DOCTYPE html>
<html>
<head>
   <title>Personagem controlável e animado</title>
   <script src="spritesheet.js"></script>
   <script src="animacao.js"></script>
   <script src="teclado.js"></script>
   <script src="sonic.js"></script>
</head>

<body>
   <canvas id="canvas_sonic" width="500" height="500"></canvas>
   <script>
      var canvas = document.getElementById('canvas_sonic');
      var context = canvas.getContext('2d');

      var teclado = new Teclado(document);
      var animacao = new Animacao(context);

      var imgSonic = new Image();
      imgSonic.src = 'spritesheet.png';

      var sonic = new Sonic(context, teclado, imgSonic);
      sonic.x = 0;
      sonic.y = 200;
      animacao.novoSprite(sonic);

      imgSonic.onload = function() {
         animacao.ligar();
      }
   </script>
</body>
</html>
---------------------------------------------------------------------------------------------------

sonic.js

var SONIC_DIREITA = 1;
var SONIC_ESQUERDA = 2;

function Sonic(context, teclado, imagem) {
   this.context = context;
   this.teclado = teclado;
   this.x = 0;
   this.y = 0;
   this.velocidade = 10;
   // Criando a spritesheet a partir da imagem recebida
   this.sheet = new Spritesheet(context, imagem, 3, 8);
   this.sheet.intervalo = 60;
   // Estado inicial
   this.andando = false;
   this.direcao = SONIC_DIREITA;
}
Sonic.prototype = {
   atualizar: function() {
      if (this.teclado.pressionada(SETA_DIREITA)) {
         // Se já não estava neste estado...
         if (! this.andando || this.direcao != SONIC_DIREITA) {
            // Seleciono o quadro da spritesheet
            this.sheet.linha = 1;
            this.sheet.coluna = 0;
         }

         // Configuro o estado atual
         this.andando = true;
         this.direcao = SONIC_DIREITA;

         // Neste estado, a animação da spritesheet deve rodar
         this.sheet.proximoQuadro();

         // Desloco o Sonic
         this.x += this.velocidade;
      }

      else if (this.teclado.pressionada(SETA_ESQUERDA)) {
         if (! this.andando || this.direcao != SONIC_ESQUERDA) {
            this.sheet.linha = 2;  // Atenção, aqui será 2!
            this.sheet.coluna = 0;
         }
         this.andando = true;
         this.direcao = SONIC_ESQUERDA;
         this.sheet.proximoQuadro();
         this.x -= this.velocidade;  // E aqui é sinal de menos!
      }

      else {
         if (this.direcao == SONIC_DIREITA)
            this.sheet.coluna = 0;
         else if (this.direcao == SONIC_ESQUERDA)
            this.sheet.coluna = 1;

         this.sheet.linha = 0;
         // Não chamo proximoQuadro!
         this.andando = false;
      }
   },
   desenhar: function() {
      this.sheet.desenhar(this.x, this.y);       
   }
}
----------------------------------------------------------------------------------------------------------


Spritesheet.js

function Spritesheet(context, imagem, linhas, colunas) {
   this.context = context;
   this.imagem = imagem;
   this.numLinhas = linhas;
   this.numColunas = colunas;
   this.intervalo = 0;
   this.linha = 0;
   this.coluna = 0;
}
Spritesheet.prototype = {
   proximoQuadro: function() {
      var agora = new Date().getTime();

      // Se ainda não tem último tempo medido
      if (! this.ultimoTempo) this.ultimoTempo = agora;

      // Já é hora de mudar de coluna?
      if (agora - this.ultimoTempo < this.intervalo) return;

      if (this.coluna < this.numColunas - 1)
         this.coluna++;
      else
         this.coluna = 0;

      // Guardar hora da última mudança
      this.ultimoTempo = agora;
   },
   desenhar: function(x, y) {
      var largura = this.imagem.width / this.numColunas;
      var altura = this.imagem.height / this.numLinhas;

      this.context.drawImage(
         this.imagem,
         largura * this.coluna,
         altura * this.linha,
         largura,
         altura,
         x,
         y,
         largura,
         altura
      );
   }
}
----------------------------------------------------------------------------------------------------
animacao.js

function Animacao(context) {
   this.context = context;
   this.sprites = [];
   this.ligado = false;
}
Animacao.prototype = {
   novoSprite: function(sprite) {
      this.sprites.push(sprite);
   },
   ligar: function() {
      this.ligado = true;
      this.proximoFrame();
   },
   desligar: function() {
      this.ligado = false;
   },
   proximoFrame: function() {
      // Posso continuar?
      if ( ! this.ligado ) return;

      // A cada ciclo, limpamos a tela ou desenhamos um fundo
      this.limparTela();

      // Atualizamos o estado dos sprites
      for (var i in this.sprites)
         this.sprites[i].atualizar();

      // Desenhamos os sprites
      for (var i in this.sprites)
         this.sprites[i].desenhar();

      // Chamamos o próximo ciclo
      var animacao = this;
      requestAnimationFrame(function() {
         animacao.proximoFrame();
      });
   },
   limparTela: function() {
      var ctx = this.context;
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
   }
}
---------------------------------------------------------------------------------------------

teclado.js

// Códigos de teclas - aqui vão todos os que forem necessários
var SETA_ESQUERDA = 37;
var SETA_DIREITA = 39;
var ESPACO = 32;

function Teclado(elemento) {
   this.elemento = elemento;

   // Array de teclas pressionadas
   this.pressionadas = [];

   // Array de teclas disparadas
   this.disparadas = [];

   // Funções de disparo registradas
   this.funcoesDisparo = [];

   var teclado = this;

   elemento.addEventListener('keydown', function(evento) {
      var tecla = evento.keyCode;  // Tornando mais legível ;)
      teclado.pressionadas[tecla] = true;

      // Disparar somente se for o primeiro keydown da tecla
      if (teclado.funcoesDisparo[tecla] && !teclado.disparadas[tecla]) {

          teclado.disparadas[tecla] = true;
          teclado.funcoesDisparo[tecla] () ;
      }
   });

   elemento.addEventListener('keyup', function(evento) {
      teclado.pressionadas[evento.keyCode] = false;
      teclado.disparadas[evento.keyCode] = false;
   });
}
Teclado.prototype = {
   pressionada: function(tecla) {
      return this.pressionadas[tecla];
   },
   disparou: function(tecla, callback) {
      this.funcoesDisparo[tecla] = callback;
   }
}


Nenhum comentário:

Postar um comentário