Prática de construção de objetos

Você está lendo a versão em inglês deste conteúdo porque ainda não há uma tradução para este idioma. Ajude-nos a traduzir este artigo!

Nos artigos anteriores, analisamos todos os detalhes essenciais da teoria e da sintaxe do objeto JavaScript, fornecendo uma base sólida para começar. Neste artigo, vamos mergulhar em um exercício prático, dando a você mais prática na construção de objetos JavaScript personalizados, com um resultado divertido e colorido.

Prerequisites: Basic computer literacy, a basic understanding of HTML and CSS, familiarity with JavaScript basics (see First steps and Building blocks) and OOJS basics (see Introduction to objects).
Objective: To get some practice with using objects and object-oriented techniques in a real world context.

Vamos devolver algumas bolas

Neste artigo, vamos escrever uma demo clássica de "bolas saltitantes", para mostrar como objetos úteis podem ser em JavaScript. Nossas bolinhas vão saltar pela tela e mudam de cor quando se tocam. O exemplo acabado vai parecer um pouco assim:

Este exemplo fará uso da Canvas API, para desenhar as bolas na tela, e da requestAnimationFrame API para animar toda a exibição — você não precisa ter nenhum conhecimento anterior sobre essas APIs e esperamos que, no momento em que você Depois de terminar este artigo, você estará interessado em explorá-los mais. Ao longo do caminho, faremos uso de alguns objetos bacanas, e mostraremos algumas técnicas legais, como bolas quicando nas paredes, e verificando se elas se chocaram (também conhecidas como detecção de colisão).

Começando

Para começar, faça cópias locais de nossos arquivos  index.html, style.css, e main.js. Estes contêm o seguinte, respectivamente:

  1. Um documento HTML muito simples com um elemento <h1>, um elemento <canvas> para desenhar nossas bolas e elementos para aplicar nosso CSS e JavaScript em nosso HTML.
  2. Alguns estilos muito simples, que servem principalmente para estilizar e posicionar o <h1>, e se livrar de qualquer barra de rolagem ou margem ao redor da borda da página (para que fique bonito e arrumado).
  3. Algum JavaScript que serve para configurar o elemento <canvas> e fornecer uma função geral que vamos usar.

A primeira parte do script é assim:

var canvas = document.querySelector('canvas');

var ctx = canvas.getContext('2d');

var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;

Esse script obtém uma referência ao elemento <canvas> e, em seguida, chama o método getContext() para nos fornecer um contexto no qual podemos começar a desenhar. A variável resultante (ctx) é o objeto que representa diretamente a área de desenho da tela e nos permite desenhar formas 2D nela.

Em seguida, definimos variáveis chamadas widthheight, e a largura e altura do elemento canvas (representado pelas propriedades canvas.widthcanvas.height) para igualar a largura e a altura da viewport do navegador (a área em que a página da Web aparece — isso pode ser obtido das propriedades Window.innerWidth e Window.innerHeight ).

Você verá aqui que estamos encadeando várias tarefas juntas, para que as variáveis sejam todas mais rápidas — isso é perfeitamente aceitável.

O último bit do script inicial é o seguinte:

function random(min, max) {
  var num = Math.floor(Math.random() * (max - min + 1)) + min;
  return num;
}

Essa função usa dois números como argumentos e retorna um número aleatório no intervalo entre os dois.

Modelando uma bola no nosso programa

Nosso programa contará com muitas bolas saltando ao redor da tela. Como todas essas bolas se comportarão da mesma maneira, faz sentido representá-las com um objeto. Vamos começar adicionando o construtor a seguir ao final do código.

function Ball(x, y, velX, velY, color, size) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.color = color;
  this.size = size;
}

Aqui incluímos alguns parâmetros que definem as propriedades que cada bola precisa para funcionar em nosso programa:

  • coordenadas x e y — coordenadas horizontal e vertical onde a bola vai começar na tela. Isso pode variar entre 0 (canto superior esquerdo) à largura e altura da janela de visualização do navegador (canto inferior direito).
  • velocidade horizontal e vertical (velXvelY) — cada bola recebe uma velocidade horizontal e vertical; em termos reais, esses valores serão adicionados regularmente aos valores das coordenadas x/y quando começarmos a animar as bolas, para movê-las tanto em cada quadro.
  • color — cada bola recebe uma cor.
  • size — cada bola recebe um tamanho — este será o seu raio, em pixels.

Isso classifica as propriedades, mas e os métodos? Queremos realmente fazer com que nossas bolas façam algo em nosso programa.

Desenhando a bola

Primeiro adicione o seguinte método draw() ao prototype do Ball():

Ball.prototype.draw = function() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

Usando esta função, podemos dizer a nossa bola para desenhar-se na tela, chamando uma série de membros do contexto de tela 2D que definimos anteriormente (ctx). O contexto é como o papel, e agora queremos comandar nossa caneta para desenhar algo nela:

  • Primeiro, usamos beginPath() para declarar que queremos desenhar uma forma no papel.
  • Em seguida, usamos fillStyle para definir a cor que queremos que a forma seja — nós a definimos como a propriedade color da nossa bola.
  • Em seguida, usamos o método  arc() para traçar uma forma de arco no papel. Seus parâmetros são:
    • A posição xy do centro do arco — estamos especificando as propriedades xy da nossa bola.
    • O raio do nosso arco — estamos especificando a propriedade size  da nossa bola.
    • Os dois últimos parâmetros especificam o número inicial e final de graus em volta do círculo em que o arco é desenhado entre eles. Aqui nós especificamos 0 graus e 2 * PI, que é o equivalente a 360 graus em radianos (irritantemente, você tem que especificar isso em radianos). Isso nos dá um círculo completo. Se você tivesse especificado apenas 1 * PI, você obteria um semicírculo (180 graus).
  • Por último, usamos o método fill(), que basicamente diz "terminar de desenhar o caminho que começamos com beginPath(), e preencher a área que ocupa com a cor que especificamos anteriormente em fillStyle."

Você pode começar a testar seu objeto já.

  1. Salve o código até o momento e carregue o arquivo HTML em um navegador.
  2. Abra o console JavaScript do navegador e, em seguida, atualize a página para que o tamanho da tela mude para a viewport menor visível deixada quando o console for aberto.
  3. Digite o seguinte para criar uma nova instância de bola:
    var testBall = new Ball(50, 100, 4, 4, 'blue', 10);
  4. Tente chamar seus membros:
    testBall.x
    testBall.size
    testBall.color
    testBall.draw()
  5. Quando você entra na última linha, você deve ver a bola se desenhando em algum lugar na sua tela.

Atualizando os dados da bola

Podemos puxar a bola em posição, mas para começar a mover a bola, precisamos de uma função de atualização de algum tipo. Adicione o seguinte código na parte inferior do seu arquivo JavaScript, para adicionar um método  update() ao prototype do Ball():

Ball.prototype.update = function() {
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}

As primeiras quatro partes da função verificam se a bola atingiu a borda da tela. Se tiver, invertemos a polaridade da velocidade relevante para fazer a bola viajar na direção oposta. Assim, por exemplo, se a bola estava viajando para cima (positivo velY), então a velocidade vertical é alterada de forma que ela comece a descer para baixo (negativo velY).

Nos quatro casos, somos:

  • Verificando se a coordenada x é maior que a largura da tela (a bola está saindo da borda direita).
  • Verificando se a coordenada x é menor que 0 (a bola está saindo da borda esquerda).
  • Verificando se a coordenada y é maior que a altura da tela (a bola está saindo da borda inferior).
  • Verificando se a coordenada y é menor que 0 (a bola está saindo da borda superior).

Em cada caso, estamos incluindo o size da bola no cálculo, porque as coordenadas x/y estão no centro da bola, mas queremos que a borda da bola saia do perímetro — não queremos a bola para ir até a metade da tela antes de começar a se recuperar.

As duas últimas linhas adicionam o valor velX à coordenada x, e o valor velY à coordenada y —  a bola está em efeito movida cada vez que este método é chamado.

Isso vai fazer por agora; vamos continuar com alguma animação!

Animando a bola

Agora vamos fazer isso divertido. Agora vamos começar a adicionar bolas à tela e a animá-las.

  1. Primeiro, precisamos de um lugar para armazenar todas as nossas bolas. O array a seguir fará esse trabalho — adicione-o ao final do seu código agora:
    var balls = [];

    Todos os programas que animam as coisas geralmente envolvem um loop de animação, que serve para atualizar as informações no programa e renderizar a visualização resultante em cada quadro da animação; esta é a base para a maioria dos jogos e outros programas.

  2. Adicione o seguinte ao final do seu código agora:
    function loop() {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
      ctx.fillRect(0, 0, width, height);
    
      while (balls.length < 25) {
        var size = random(10,20);
        var ball = new Ball(
          // ball position always drawn at least one ball width
          // away from the edge of the canvas, to avoid drawing errors
          random(0 + size,width - size),
          random(0 + size,height - size),
          random(-7,7),
          random(-7,7),
          'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')',
          size
        );
        balls.push(ball);
      }
    
      for (var i = 0; i < balls.length; i++) {
        balls[i].draw();
        balls[i].update();
      }
    
      requestAnimationFrame(loop);
    }

    Nossa função loop() faz o seguinte:

    • Define a cor de preenchimento da tela como preto semitransparente e desenha um retângulo da cor em toda a largura e altura da tela, usando fillRect() (os quatro parâmetros fornecem uma coordenada de início e uma largura e altura para o retângulo desenhado ). Isso serve para encobrir o desenho do quadro anterior antes que o próximo seja desenhado. Se você não fizer isso, você verá apenas longas cobras se movimentando ao redor da tela, em vez de mover as bolas! A cor do preenchimento é definida como semitransparente, rgba(0,0,0,0.25), para permitir que os poucos quadros anteriores brilhem levemente, produzindo as pequenas trilhas atrás das bolas à medida que elas se movem. Se você mudou 0,25 para 1, você não vai mais vê-los. Tente variar esse número para ver o efeito que ele tem.
    • Cria uma nova instância de nossa  Ball() usando valores aleatórios gerados com a nossa função  random() então push()para o final de nosso array de bolas, mas somente enquanto o número de bolas no array é menor que 25. Então quando temos 25 bolas na tela, não aparecem mais bolas. Você pode tentar variar o número emballs.length < 25 para obter mais ou menos bolas na tela. Dependendo de quanto poder de processamento seu computador / navegador possui, especificar vários milhares de bolas pode retardar bastante a animação!
    • Faz um loop em todas as balls no array de bolas e executa a função draw()update() de cada bola para desenhar cada uma delas na tela, depois faz as atualizações necessárias para a posição e a velocidade no tempo para o próximo quadro.
    • Executa a função novamente usando o método requestAnimationFrame() — quando esse método é executado constantemente e passa o mesmo nome de função, ele executará essa função um número definido de vezes por segundo para criar uma animação suave. Isso geralmente é feito de forma recursiva — o que significa que a função está chamando a si mesma toda vez que é executada, portanto, ela será executada repetidas vezes.
  3. Por último mas não menos importante, adicione a seguinte linha à parte inferior do seu código — precisamos chamar a função uma vez para iniciar a animação.
    loop();

É isso para o básico — tente salvar e atualizar para testar suas bolas quicando!

Adicionando detecção de colisão

Agora, para um pouco de diversão, vamos adicionar alguma detecção de colisão ao nosso programa, para que nossas bolas saibam quando bateram em outra bola.

  1. Primeiro de tudo, adicione a seguinte definição de método abaixo onde você definiu o método  update() (ou seja, o bloco Ball.prototype.update).
    Ball.prototype.collisionDetect = function() {
      for (var j = 0; j < balls.length; j++) {
        if (!(this === balls[j])) {
          var dx = this.x - balls[j].x;
          var dy = this.y - balls[j].y;
          var distance = Math.sqrt(dx * dx + dy * dy);
    
          if (distance < this.size + balls[j].size) {
            balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')';
          }
        }
      }
    }

    Esse método é um pouco complexo, então não se preocupe se você não entender exatamente como isso funciona agora. Uma explicação segue:

    • Para cada bola, precisamos checar todas as outras bolas para ver se ela colidiu com a bola atual. Para fazer isso, abrimos outro loop for para percorrer todas as bolas no array balls[].
    • Imediatamente dentro de nosso loop for, usamos uma instrução  if para verificar se a bola atual em loop é a mesma bola que estamos verificando no momento. Não queremos verificar se uma bola colidiu consigo mesma! Para fazer isso, verificamos se a bola atual (ou seja, a bola cujo método collisionDetect está sendo invocado) é a mesma que a bola de loop (ou seja, a bola que está sendo referenciada pela iteração atual do loop for no collisionDetect método). Nós então usamos ! para negar a verificação, para que o código dentro da instrução if seja executado apenas se eles não forem iguais.
    • Em seguida, usamos um algoritmo comum para verificar a colisão de dois círculos. Estamos basicamente verificando se alguma das áreas dos dois círculos se sobrepõe. Isso é explicado ainda mais na 2D collision detection.
    • Se uma colisão for detectada, o código dentro da instrução if interna será executado. Neste caso, estamos apenas definindo a propriedade color de ambos os círculos para uma nova cor aleatória. Poderíamos ter feito algo muito mais complexo, como fazer com que as bolas saltassem umas das outras de forma realista, mas isso teria sido muito mais complexo de implementar. Para essas simulações físicas, os desenvolvedores tendem a usar jogos ou bibliotecas físicas, como PhysicsJS, matter.js, Phaser, etc.
  2. Você também precisa chamar esse método em cada quadro da animação. Adicione o seguinte abaixo do balls[i].update();:
    balls[i].collisionDetect();
  3. Salve e atualize a demonstração novamente, e você verá suas bolas mudando de cor quando colidirem!

Note: If you have trouble getting this example to work, try comparing your JavaScript code against our finished version (also see it running live).

Sumário

Esperamos que você tenha se divertido escrevendo seu próprio exemplo de bolas saltitonas aleatórias do mundo real, usando várias técnicas orientadas a objetos e objetos de todo o módulo! Isso deve ter lhe dado alguma prática útil no uso de objetos e um bom contexto do mundo real.

É isso para artigos de objetos — tudo o que resta agora é para você testar suas habilidades na avaliação de objetos.

See also

 

In this module