quinta-feira, 24 de julho de 2014

Workers em javascript

O Senhor é o meu rochedo, e o meu lugar forte, e o meu libertador; o meu Deus, a minha fortaleza, em quem confio; o meu escudo, a força da minha salvação, e o meu alto refúgio. (Salmos 18:2)

WebWorkers são, basicamente, "scripts trabalhadores da WEB". Basicamente, são, semelhante á qualquer outro arquivo javascript, ou seja, scripts que interagem com a página principal. Porém, há uma pequena diferença: Durante a execução de qualquer instrução, seja uma requisição ou algum tipo de processamento, a outra instrução aguarda o fim da primeira. A execução de instruções em javascript é linear e não paralela. O navegador interpreta e executa linha a linha os comandos do bloco de intruções. Por exemplo: Quando há uma requisição em andamento, o interpretador simplesmente para, até a requisição estiver concluída. Só depois, segue a execução até a próxima linha.

No caso de WebWorkers, é diferente: A página principal aciona ou manda uma mensagem para algum script worker, e o mesmo, em executa determinado processamento em paralelo. Ou seja, a página principal continua executando seu bloco de instruções sem aguardar o fim da linha anterior.

Este mecanismo funciona graças á uma eficiente troca de mensagens entre o script e a página principal: Quando a página principal aciona o script (Evento postMessage), é executado o evento onMessage() no worker, que irá retornar sua resposta á página principal através do método postaMessage(). A resposta do worker estará no atributo data, do manipulador de evento event.

O exemplo consiste em um campo, um container e um botão para enviar. Depois que você digita algo, e clique em ENVIAR, o valor digitado é enviado ao worker, que retorna uma resposta com o valor, e alguma mensagem aleatória, como se fosse um chat.

 


onconnect = function (event) {

 
 var newPort = event.ports[0];
 
 var msgs = new Array();
 msgs.push("Como c ta");
 msgs.push("DDDDDDDDD");
 msgs.push("MMMMMMMMMMMMMMM");
 

 
 newPort.postMessage("Estabelecida conexao: ");
 
 newPort.onmessage = function (event) {
  var x = Math.floor(Math.random() * (msgs.length));
  var m = msgs[x];
  newPort.postMessage("Recebido: " + event.data); newPort.postMessage("Enviado: " +  m); 
 };
  //newPort.postMessage('ready!');
};

LINK PRO EXEMPLO
BAIXAR EXEMPLO

terça-feira, 1 de julho de 2014

Colisões com Easeljs

Assim diz o Senhor, o teu Redentor, o Santo de Israel: Eu sou o Senhor teu Deus, que te ensina o que é útil, e te guia pelo caminho em que deves andar. (Isaías 48:17)

Uma colisão é o choque entre dois corpos num determinado espaço. É, basicamente, o que acontece quando 2 carros se batem em alta velocidade. Também é por causa disto que você não atravessa paredes, tendo sua liberdade  de andar e explorar o espaço limitada. Este conceito é bastante utilizado na criação de jogos, pois, na grande maioria deles, há colisão ou choque entre corpos. Sem a aplicação deste conceito, seu objeto poderia tranquilamente atravessar uma parede sem que você queira.

O nosso exemplo se baseará no mesmo apresentado na postagem anterior: Criando animações com EaselJs. Porém ,com algumas diferenças. Nesta demonstração, será utilizado canvas (Onde se desenham animações específicas), javascript (Linguagem de script utilizada nos navegadores) e easeljs (Biblioteca javascript que encapsula alguns métodos próprios para lidar com CANVAS). A documentação desta biblioteca está disponível em EaselJs

Será criada uma animação que se consistirá no seguinte: Duas bolas (Vermelha e azul). A bola azul irá onde sempre seguir o quadrado laranja. O quadrado laranja será o ponto onde você pode fazer clique ou toque (Caso utilize um dispositivo TOUCH). Depois de um tempo,  irá aparecer um círculo negro, que é aonde, empregando os métodos de colisão, você deverá levar a bola vermelha.

Então, seguem abaixo as propriedades das 2 bolas:

 function constroe(){
  pos = definePosicaoRandomica(w,l);
  bola.x = pos.x;
  bola.y = pos.y;
  bola.vx = 4;
  bola.vy = 4;
  bola.r = r;
  
  pos = definePosicaoRandomica(w,l);
  red.x = pos.x;
  red.y = pos.y;
  red.vx = 2;
  red.vy = 2;
  red.r = r;

  pos = definePosicaoRandomica(w,l);
  saida.x = pos.x;
  saida.y = pos.y;
  saida.r = 20;
 }

Quando a página é carregada, é executado o método init(). Este método, basicamente, instancia os objetos, desenha os mesmos na tela, e associa eventos de clique e de toque á determinados métodos. 

 function init() {
  w = document.getElementById("demoCanvas").width;
  l = document.getElementById("demoCanvas").height;
  stage = new createjs.Stage("demoCanvas");
  r = 10;
  bola = new createjs.Shape();
  red = new createjs.Shape();
  es = new createjs.Shape();
  saida = new createjs.Shape();
  saida.ex = false;
        var is_touch_device = 'ontouchstart' in document.documentElement;

  constroe();
  
  desenha();

  createjs.Ticker.init();

  createjs.Ticker.on("tick", tick);
  
  
  createjs.Ticker.setFPS(50);
  
 
  if(is_touch_device === true){
   document.getElementById("demoCanvas").addEventListener("touchstart",handleTouch,false);
  }else{
   document.getElementById("demoCanvas").onclick = function(e){
    handleClique(e);
   }
  }
  
 }

 

Como você deve perceber, quando houve clique em alguma área delimitada pelo canvas, ou algum toque, são executados métodos específicos de toque ou de clique. Porém, ambos fazem a mesma coisa: Capturar coordenadas do mouse ou do toque. Isto para que, onde você tocar ou clicar, ficará o ponto laranja. O ponto laranja será seguido pela bola azul, graças ao método perseguicao(). 

 function handleTouch(e){
  
  es.x = 0;
  es.y = 0;
  var coords = getCoordsTouch(e);
  es.x = coords.x;
  es.y = coords.y;

 }
 
 function getCoordsTouch(event){
  var saida = {};
  saida.x = event.targetTouches[0].pageX - document.getElementById("demoCanvas").offsetLeft;
  saida.y = event.targetTouches[0].pageY - document.getElementById("demoCanvas").offsetTop;
  
  return saida;
 }
 function handleClique(e){
  es.x = 0;
  es.y = 0;
  
  var pX;
  var pY;
  pX = e.pageX - document.getElementById("demoCanvas").offsetLeft;
  pY = e.pageY - document.getElementById("demoCanvas").offsetTop;
  es.x = pX;
  es.y = pY;

}
 function perseguicao(obj1,obj2){
  // Animação de perseguição
  if(obj1.x < obj2.x){
   if(obj1.vx < 0){
    obj1.vx *= -1;
   }
  }else if(obj1.x > obj2.x){
   if(obj1.vx > 0){
    obj1.vx *= -1;
   }  
  }
  
  if(obj1.y < obj2.y){
   if(obj1.vy < 0){
    obj1.vy *= -1;
   }  
  }else if(obj1.y > obj2.y){
   if(obj1.vy > 0){
    obj1.vy *= -1;
   } 
  }
 }
 

 

A função tick() será executada á cada 50 milisegundos, sendo a função responsável pela continuidade e por dar vida á animação.

 

 function tick(event) {
  perseguicao(bola,es);
  
  
  bola.x += bola.vx;
  bola.y += bola.vy;
  
  red.x += red.vx;
  red.y += red.vy;

  if(checaColisao(bola,red) === true  ){
   if(red.x > bola.x){
    if(red.vx < 0){
     red.vx *= -1;
     bola.vx *= -1;
    }
   }else if(red.x < bola.x){
    if(red.vx > 0){
     red.vx *= -1;
     bola.vx *= -1;
    }
   }
   
   if(red.y > bola.y){
    if(red.vy < 0){
     red.vy *= -1;
     bola.vy *= -1;

    }
   }else if(red.y < bola.y){
    if(red.vy > 0){
     red.vy *= -1;
     bola.vy *= -1;

    }
   } 
   

  }
  
  
  checaLimites(bola);
  
  checaLimites(red);
  
  if(createjs.Ticker.getTime() > 10000){
   saida.ex = true;
   if(checaColisao(red,saida) === true){
    alert("FINISH");
    
    createjs.Ticker.reset();
    

    // Rever como reexecutar o ticker
    init();
   }
  }
  
  stage.removeAllChildren();

  desenha();

  stage.update(event);
 }

 

Vejamos como serão tratadas as colisões nesta animação, que ocorrem entre a bolinha azul e a vermelha: 

Primeiramente, na função tick(), especificamente no método checaColisao(), é feita uma verificação. Nesta checagem, basicamente, é calculada a distância entre estes dois objetos, utilizando o princípio de distância de dois pontos.  Caso queira saber mais, acesse Distância entre dois pontos. Se houve colisão, a bolinha vermelha é empurrada, graças ao impacto trazido pela bola azul. Logo, como houve resistência, o mesmo acontece com a bolinha azul. 

 function checaColisao(obj1,obj2){
        var dX = obj2.x - obj1.x;
        var dY = obj2.y - obj1.y;
        var distance = Math.sqrt((dX * dX) + (dY * dY));
        if(distance < (obj1.r + obj2.r )){
         return true;
        }
        return false;
 }

É verificado se algum dos elementos se choca com as bordas da tela, através do método checaLimites(), chamado  dentro de tick(). Se sim, então a parede reflete o impacto recebido pelo corpo.

 function checaLimites(obj){
  if( (obj.x + obj.r) > w ){
   obj.vx *= -1;
  }else if( (obj.x-obj.r ) < 0){
   obj.vx *= -1;
  }
  

  if( (obj.y + obj.r) > l ){
   obj.vy *= -1;
  }else if( (obj.y-obj.r) < 0){
   obj.vy *= -1;
  } 
 }

 

 Depois de 10 segundos, aparece um círculo negro, que é para onde você deve levar o círculo azul. Se houve colisão entre a bola azul e o círculo negro, então, o jogo se encerra. 

Links:

Página de testes
Download
Outro exemplo de colisões (De um cara que manja muito, que não sou eu!)