If you're seeing this message, it means we're having trouble loading external resources on our website.

Se você está atrás de um filtro da Web, certifique-se que os domínios *.kastatic.org e *.kasandbox.org estão desbloqueados.

Conteúdo principal

Movimento de vetores

A matemática vetorial parece algo que nós deveríamos saber, mas por quê? Como isso vai, de fato, ajudar-nos a escrever códigos? A verdade é que devemos ter um pouco de paciência. Ainda vai levar um tempo para compreendermos completamente as maravilhas da utilização de PVector.
Na verdade, isso é muito comum quando estamos aprendendo uma nova estrutura de dados. Por exemplo, quando você aprendeu sobre um array pela primeira vez, pareceu que daria muito mais trabalho utilizar um array do que criar várias variáveis para coisas diferentes. Mas esse plano não funciona quando você precisa de cem, mil ou dez mil coisas.
O mesmo vale para PVector. O que parece ser muito mais trabalhoso agora, vai valer a pena depois. E você não vai ter que esperar muito, já que sua recompensa chegará no próximo capítulo.

Velocidade

Por ora, no entanto, precisamos nos concentrar na simplicidade. O que quer dizer programação de movimento usando vetores? Vimos o princípio disso no exemplo da bola quicando. Um objeto na tela possui uma posição (onde ele se encontra em um dado momento), bem como uma velocidade (instruções para como ele deverá se mover de um momento a outro). A velocidade é somada à posição:
position.add(velocity);
E então desenhamos o objeto nesta localização:
ellipse(position.x, position.y, 16, 16);
Este é o Motion 101:
  • Somar a velocidade à posição
  • Desenhar o objeto na posição
No exemplo da bola quicando, todo esse código se processou no interior da função draw (desenhar) do ProcessingJS. O que nós queremos fazer agora é avançar para encapsular toda a lógica de movimento dentro de um objeto . Desta forma, podemos criar uma base para a programação de objetos em movimento em todos os nossos programas de ProcessingJS.
Neste caso, vamos criar um objeto "Mover" genérico que descreverá algo movendo pela tela. Portanto, devemos considerar as seguintes questões:
  • Que dados um objeto "mover" possui?
  • Que funcionalidade tem um objeto "mover"?
Nosso algoritmo Motion 101 nos dá as respostas para essas perguntas. Um objeto Mover possui dois tipos de dados: postion (posição) e velocity (velocidade), os quais são objetos PVector. Podemos começar escrevendo a função construtora que inicializa essas propriedades com valores aleatórios apropriados:
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
Sua funcionalidade é quase igualmente simples. O "Mover" precisa se movimentar e precisa ser visto. Implementaremos estas necessidades como métodos chamados update() e display(). Colocaremos toda o código da lógica de movimento em update() e desenharemo-lo em display().
Mover.prototype.update = function() {
  this.position.add(this.velocity);
};

Mover.prototype.display = function() {
  stroke(0);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 48, 48);
};
Se a programação orientada a objetos é novidade para você, um aspecto aqui pode parecer um pouco confuso. Afinal, passamos o início deste capítulo discutindo PVector. O objeto PVector é um modelo para produzir os objetos posição e velocidade. Então, o que eles estão fazendo dentro de outro objeto, o objeto Mover? Na verdade, isso é perfeitamente normal na orientação a objetos. Um objeto é simplesmente algo que contém dados (e funcionalidade). Esses dados podem ser números, strings, arrays ou outros objetos! Veremos isso repetidas vezes ao longo do curso. Por exemplo, no tutorial de Partículas vamos escrever um objeto para descrever um sistema de partículas. O objeto ParticleSystem (do inglês, "sistema de partículas") terá como seus dados um array de objetos Particle…e cada objeto Particle terá como dados inúmeros objetos PVector!
Vamos finalizar o objeto Mover incorporando uma função para determinar o comportamento do objeto ao alcançar as bordas da janela. Por ora, vamos fazer algo simples e simplesmente fazê-la contornar os cantos:
Mover.prototype.checkEdges = function() {

  if (this.position.x > width) {
    this.position.x = 0;
  } 
  else if (this.position.x < 0) {
    this.position.x = width;
  }

  if (this.position.y > height) {
    this.position.y = 0;
  } 
  else if (this.position.y < 0) {
    this.position.y = height;
  }
};
Agora que o objeto Mover está pronto, podemos olhar o que é preciso fazer no programa principal. Primeiramente, declaramos e inicializamos uma nova instância de Mover.
var mover = new Mover();
Então, chamamos as funções apropriadas em draw:
draw = function() {
  background(255, 255, 255);

  mover.update();
  mover.checkEdges();
  mover.display(); 
};
Aqui está o exemplo funcional. Tente brincar com os números e comentar o código e veja o que acontece:

Aceleração

OK. A essa altura, devemos estar acostumados com duas coisas: (1) o que é um PVector e (2) como usar PVector em um objeto para registrar sua posição e seu movimento. Esse é um excelente primeiro passo e merece uma salva de palmas. Antes de plateias ovacionando e fãs aos berros, contudo, precisamos dar mais um grande passo adiante. No final das contas, assistir ao exemplo Motion 101 é entediante — o círculo nunca ganha velocidade, nunca perde, e nunca se vira. Para movimentos mais interessantes, que se pareçam com o que vemos no mundo real, precisamos incluir mais um PVector ao nosso objeto Mover— a aceleração.
A definição estrita de aceleração que usamos aqui é: a taxa de variação da velocidade. Pensemos sobre essa definição por um momento. Seria este um novo conceito? Na verdade, não. A velocidade é definida como a taxa de variação da posição. Essencialmente, estamos desenvolvendo um efeito "cascata". A aceleração afeta a velocidade, que, por sua vez, afeta a posição (isso se tornará ainda mais crucial no próximo capítulo, quando veremos como as forças afetam a aceleração, que afeta a velocidade, que afeta a posição). No código, lê-se:
velocity.add(acceleration);
position.add(velocity);
Como um exercício, deste ponto em diante, vamos criar uma regra para nós mesmos. Escreveremos cada exemplo no resto destes tutoriais sem nunca alterar os valores de velocidade e posição (exceto para inicializá-los). Em outras palavras, nosso objetivo agora para ao programar movimentos é: criar um algoritmo para calcular a aceleração e deixar o efeito de cascata fazer a sua mágica. (Na verdade, você encontrará razões para quebrar essa regra, mas ela é importante para ilustrar os princípios por trás do nosso algoritmo de movimento). Então, precisamos propor algumas formas de calcular a aceleração:
  1. Uma aceleração constante
  2. Uma aceleração totalmente aleatória
  3. Aceleração em direção ao mouse
O Algoritmo n.° 1 , uma aceleração constante, não é particularmente interessante, mas é o mais simples e nos ajudará a introduzir aceleração no nosso código.
A primeira coisa que precisamos fazer é adicionar outra propriedade PVector ao construtor Mover para representar a aceleração. Inicializaremos em (0,001;0,01) e manteremos este valor para sempre, visto que o nosso algoritmo presente é de aceleração constante. Você deve estar pensando, "Poxa, esses valores parecem desprezivelmente pequenos!". É verdade, eles são bastante diminutos. É importante perceber que os nossos valores de aceleração (mensurados em pixels) vão acumular ao longo do tempo na velocidade—aproximadamente trinta vezes por segundo, dependendo da taxa de quadros no nosso esboço. Portanto, para manter a magnitude do vetor velocidade dentro de uma faixa razoável, nossos valores de aceleração devem começar e se manter bem pequenos.
var Mover = function() {
  this.position = new PVector(width/2,height/2);
  this.velocity = new PVector(0, 0);
  this.acceleration = new PVector(-0.001, 0.01);
};
Repare acima que também iniciamos a velocidade em 0—porque sabemos que a aceleraremos conforme o programa roda. Faremos isto no método update():
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);  
};
Uma vez que estamos continuamente incrementando a velocidade, correremos o risco de nossos valores de velocidade se tornarem incrivelmente grandes. Se deixarmos o programa rodar por tempo suficiente. Queremos limitar a velocidade a um máximo. Podemos fazê-lo usando o método limit de PVector, que restringe um vetor a uma dada magnitude.
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Isto se traduz para o seguinte:
Qual é a magnitude da velocidade? Se é menor que 10, sem problemas; deixe-a como está. Se for maior que 10, todavia, reduza-a a 10!
Vamos dar uma olhada nas mudanças no objeto Mover, completo com acceleration e limit():
Agora prossigamos ao Algoritmo n.° 2, uma aceleração totalmente aleatória. Neste caso, em vez de inicializar a aceleração no construtor do objeto, queremos tomar uma nova aceleração para cada ciclo, isto é, sempre que update() é chamado.
Mover.prototype.update = function() {
  this.acceleration = PVector.random2D();
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Como o vetor aleatório é normalizado, podemos tentar escalá-lo com duas técnicas diferentes:
  1. Escalando a aceleração para um valor constante:
    acceleration = PVector.random2D();
    acceleration.mult(0.5);
    
  1. Escalando a aceleração a um valor aleatório
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
Por mais que isto pareça algo óbvio, é crucial entender que a aceleração não se refere meramente a impulsionar ou retardar um objeto em movimento, mas qualquer variação na velocidade, tanto em magnitude quanto em direção. A aceleração é usada para conduzir um objeto, e veremos isto de novo e de novo em capítulos futuros, conforme começarmos a programar objetos que fazem decisões sobre como se mover pela tela.

Este curso "Natural Simulations" é um derivado do "The Nature of Code" por Daniel Shiffman, usado sob a Creative Commons Attribution-NonCommercial 3.0 Unported License.

Quer participar da conversa?

Você entende inglês? Clique aqui para ver mais debates na versão em inglês do site da Khan Academy.