Animações

Para iniciar a linha de raciocínio, devemos nos perguntar:
O que é uma animação?

Uma animação é exatamente uma sequência de imagens, que, quando exibidas sequencialmente, formam um determinado movimento.

Utilizando o javascript como recurso, podemos simular um processo de sequência e desenhar (renderizar) o que queremos animar, por exemplo:

//Declara a variável de contagem
var c = 0;

//função que executa o passo (step)
var step = function(){
  //Aumenta o contador de steps
  c += 1;

  //Desenha o frame
  renderizarFrame(c);
};

//Coloca a função step para ser executada a cada 40 milissegundos
setInterval(step, 40);

Sim, já vimos essa regra no último tutorial, mas um pouco mais de explicações sobre esse assunto não vai fazer mal à ninguém.
A nossa função de renderizar frame é onde vai ocorrer a mágica. Baseado no valor da variável c, colocaremos um quadrado em uma posição diferente, assim criando o efeito de movimentação:

// Define qual é a velocidade que o retângulo vai se movimentar
var renderizarFrame = function(c){
  // Limpa o canvas, para não desenhar um retângulo em cima do outro e causar o efeito de "borrão". Experimente comentar a linha abaixo caso esteja curioso
  ctx.clearRect(0,0,canvas.width,canvas.height);


  //desenha o retângulo, a variável c é usada 
  ctx.fillStyle = '#0000FF'; //a definição de fillStyle poderia ocorrer fora dessa função para melhorar a performance, mas e se tivéssemos dois quadrados, por exemplo?
  ctx.fillRect(c, 50, 100, 80);
};

var velocidade = 1.1;
//Vamos alterar a função step para utilizar a velocidade dinâmica:
var step = function(){
  //Aumenta o contador de steps
  c += velocidade;

  //Desenha o frame
  renderizarFrame(c);
};

(Não se esqueça de atualizar a sua função step como fiz acima)

Ok, mas tem algo estranho. Nosso movimento parece estar “travando” em alguns momentos.
Isso ocorre por que quando o navegador usa o método setInterval, ele não se importa se o canvas terminou seu processamento, ele SEMPRE fará de tudo para atualizar a cada 40 milisegundos, custe o que custar. Isso sobrecarrega nosso motor de renderização.

Para solucionar esse problema, os browsers têm métodos para nos dizer quando eles estão prontos para desenhar novamente:

  • requestAnimationFrame //Browsers em suas últimas versões
  • webkitRequestAnimationFrame //Google chrome em versões não tão recentes
  • mozRequestAnimationFrame //Firefox
  • funcão declarada com setTimeout dentro //IEs antigos

Para suprir a necessidade de todos os browsers, vamos encapsular todos esses métodos em um método centralizado (coloque antes da definição de step):

var requestAnimFrame = 
  window.requestAnimationFrame   ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame    ||
  function( callback ){
    //Tenta chamar o método callback 60 vezes por segundo
    window.setTimeout(callback, 1000/60); 
  };

var step = function(){
  //Quando o browser estiver pronto para desenhar, executa o método step (ele mesmo)
  requestAnimFrame(step);

  //Aumenta o contador de steps
  c += velocidade;

  //Desenha o frame
  renderizarFrame(c);
  };
}

Agora não precisamos mais do antigo setInterval, mas precisamos iniciar nosso motor chamando o método step pela primeira vez:

step();
//Não utilizamos mais setInterval devido a nossa lógica de requestAnimationFrame
//setInterval(step, 40);

Pronto. Agora temos um modelo funcional de animação suave.

Como transformar isso em um jogo?
O que difere uma animação de um jogo é a interatividade, então, vamos adicionar um pouco (só um pouco) de interatividade no nosso jogo. Colocaremos um acelerador de velocidade: as setas do teclado:

// Define a captura de eventos do teclado para alternar a velocidade de acordo com a seta pressionada
document.onkeydown = function(e){
  //Caso alguma seta seja pressionada, temos que responder ao movimento:

  switch (e.keyCode){
    case 39:
      //Aumenta a velocidade (anda pra direita)
      velocidade += 0.5;
    break;
    case 37:
      //Reduz a velocidade (anda pra esquerda)
      velocidade += 0.5;
    break;
    default:
      return;
  }
  return false;
}

Para facilitar seu teste, defina o valor inicial da variável velocidade para 0.
Agora que o retângulo não move, seria bom adicionar uma mensagem no método de desenho:

var renderizarFrame = function(c){
  // Limpa o canvas, para não desenhar um retângulo em cima do outro e causar o efeito de "borrão". Experimente comentar a linha abaixo caso esteja curioso
  ctx.clearRect(0,0,canvas.width,canvas.height);

  // define a posição x do retângulo baseando-se no contador e na velocidade:
  var x = c;

  //desenha o retângulo
  ctx.fillStyle = '#0000FF'; //a definição de fillStyle poderia ocorrer fora dessa função para melhorar a performance, mas e se tivéssemos dois quadrados, por exemplo?
  ctx.fillRect(x, 50, 100, 80);

  //desenha a frase de ajuda
  ctx.font="20px Verdana";
  ctx.fillStyle="green";
  ctx.fillText("Pressione barra de espaços para acelerar",10,30);

};

Na próxima parte, vamos melhorar (e muito) nosso sistema de controle (input) e também vamos usar alguns conceitos básicos de física pra dar mais realismo ao jogo. Também voltaremos a orientar nosso código a objetos e mostrar algumas estruturas básicas de uma Game Engine.

Fontes:
http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
https://pt.wikipedia.org/wiki/Animação

Comentários

⬆︎TOPO