Conteúdo principal
Programação
Curso: Programação > Unidade 5
Lição 5: Forças- Leis de movimento de Newton
- Desafio: Balão flutuante
- Movimento de diversos objetos
- Modelando a gravidade e o atrito
- Resistência do ar e dos fluidos
- Atração gravitacional
- Desafio: Gerador de arte
- Atração mútua
- Projeto: Ameaças e benefícios para a criatura
© 2023 Khan AcademyTermos de usoPolítica de privacidadeAviso de cookies
Atração gravitacional
Provavelmente a força mais famosa de todas é a gravidade. Nós, humanos na Terra, pensamos na gravidade como a maçã acertando a cabeça de Isaac Newton. Gravidade significa que as coisas caem. Mas essa é apenas a nossa experiência da gravidade. Na realidade, da mesma forma que a Terra atrai a maçã para si devido a uma força gravitacional, a maçã também atrai a Terra. A questão é que a Terra é tão massiva que ela suprime todas as interações gravitacionais de todos os outros corpos no planeta. Cada corpo com massa exerce uma força gravitacional em todos os outros corpos. E existe uma fórmula para calcular a intensidade dessas forças, conforme ilustrado no diagrama abaixo:
Vamos examinar esta fórmula um pouco mais de perto.
F
refere-se à força gravitacional, o vetor que no final queremos calcular e passar para a funçãoapplyForce()
.G
é a constante gravitacional universal, que no nosso mundo é igual a 6,67428 x 10^-11 metros ao cubo por quilograma por segundo quadrado. Este é um número bastante importante, se o seu nome é Isaac Newton ou Albert Einstein. Ele não é um número importante se você é um programador ProcessingJS. De novo, ele é uma constante que nós podemos usar para fazer as forças no nosso mundo serem mais fracas ou mais fortes. Apenas assumindo o valor um e a ignorando não é uma má escolha.- m, start subscript, 1, end subscript e m, start subscript, 2, end subscript são as massas dos objetos
1
e2
. Como nós vimos com a segunda lei de Newton (F, with, vector, on top, equals, M, A, with, vector, on top), massa também é algo que podemos escolher ignorar. Afinal, formas desenhadas na tela na verdade não têm massa. Porém, se nós mantivermos esses valores, podemos criar simulações mais interessantes nas quais objetos “maiores” exercem uma força gravitacional maior do que os menores. - r, with, hat, on top refere-se ao vetor unitário apontando do objeto
1
para o objeto2
. Veremos em um momento que nós podemos computar esse vetor subtraindo a posição de um objeto da posição do outro. - r, squared refere-se à distância entre os dois objetos ao quadrado. Vamos parar um momento para pensar um pouco mais sobre isso. Com tudo da parte de cima da fórmula—
G
,m_1
, m, start subscript, 2, end subscript—quanto maior o seu valor, mais forte é a força. Grande massa, grande força. GrandeG
, grande força. Agora, quando dividimos por algo, temos o contrário. A intensidade da força é inversamente proporcional ao quadrado da distância. Quanto mais longe um objeto está, mais fraca é a força; quanto mais perto, mais forte é a força.
Esperamos que agora a fórmula faça algum sentido para nós. Nós vimos um diagrama e dissecamos individualmente os componentes da fórmula. Agora é hora de descobrir como traduzir a matemática para código ProcessingJ. Vamos fazer as seguintes suposições.
Temos dois objetos, e:
- Cada objeto tem uma localização
PVector
:location1
elocation2
. - Cada objeto tem uma massa numérica:
mass1
emass2
. - Existe uma variável
G
para a constante gravitacional universal.
Dadas essas hipóteses, nós queremos calcular uma
PVector force
, a força da gravidade. Faremos isso em duas etapas. Primeiro, vamos calcular a direção da força r, with, hat, on top na equação acima. Depois, vamos calcular a intensidade da força de acordo com as massas e distâncias.Lembra quando nós descobrimos como fazer um objeto acelerar em direção ao mouse? Vamos usar a mesma lógica aqui.
Um vetor é a diferença entre dois pontos. Para fazer um vetor que apontava do círculo para o mouse, simplesmente subtraímos um ponto do outro:
var dir = PVector.sub(mouse, location);
No nosso caso, a direção da força de atração que o objeto 1 exerce sobre o objeto 2 é igual a:
var dir = PVector.sub(location1, location2);
Não se esqueça que já que queremos um vetor unitário, um vetor que nos indique apenas a direção, nós precisaremos normalizá-lo depois de subtrair as posições:
dir.normalize();
OK, nós temos a direção da força. Agora nós apenas precisamos calcular a magnitude e dimensionar o vetor adequadamente.
var m = (G * mass1 * mass2) / (distance * distance);
dir.mult(m);
O único problema é que nós não sabemos a distância.
G
, mass1
, e mass2 são todos dados, mas nós precisaremos na verdade calcular a distância antes que o código acima funcione. Nós não acabamos de criar um vetor que aponta de uma posição para outra? Não seria o comprimento desse vetor igual à distância entre dois objetos?Bem, se adicionarmos apenas mais uma linha de código e pegarmos a magnitude do vetor antes de normalizá-lo, então nós vamos ter a distância.
// Vetor que aponta de um objeto para outro
var force = PVector.sub(location1, location2);
// Comprimento (magnitude) desse vetor é a distância entre os dois objetos.
var distance = force.mag();
// Use a fórmula da gravidade para calcular a intensidade da força.
var strength = (G * mass1 * mass2) / (distance * distance);
// Normalize e ajuste a escala do vetor força para a magnitude apropriada.
force.normalize();
force.mult(strength);
Note que também renomeei
PVector
“dir” como “force.” Afinal, quando terminarmos os cálculos, o PVector
com que começamos vai acabar sendo o vetor força que queríamos desde o início.Agora que nós trabalhamos a matemática e o código para calcular uma força de atração (emulando a gravidade), nós precisamos voltar nossa atenção para aplicar esta técnica no contexto um programa ProcessingJS real. Mais cedo nessa seção, nós criamos um objeto simples
Mover
—um objeto com uma posição PVector
, velocidade, e aceleração assim como um método applyForce()
. Vamos pegar essa mesma classe e colocá-la em um programa com:- Um único objeto
Mover
. - Um único objeto
Attractor
(um novo tipo de objeto que vai ter uma posição fixa).
O objeto
Mover
irá experimentar uma força gravitacional que puxa em direção ao objeto Attractor
, como ilustrado no diagrama.Nós podemos começar fazendo um objeto
Attractor
bastante simples—dando-lhe uma posição e uma massa, juntamente com um método para exibir-se (atrelando a massa ao tamanho).var Attractor = function() {
this.position = new PVector(width/2, height/2);
this.mass = 20;
this.G = 1;
this.dragOffset = new PVector(0, 0);
this.dragging = false;
this.rollover = false;
};
// Método para exibir
Attractor.prototype.display = function() {
ellipseMode(CENTER);
strokeWeight(4);
stroke(0);
fill(175, 175, 175, 200);
ellipse(this.position.x, this.position.y, this.mass*2, this.mass*2);
};
Depois de definir isso, podemos criar uma instância do objeto do tipo
Attractor
.var mover = new Mover();
var attractor = new Attractor();
draw = function() {
background(50, 50, 50);
attractor.display();
mover.update();
mover.display();
};
Essa é uma boa estrutura: um programa principal com um objeto
Mover
e um objeto Attractor
. O último pedaço do quebra-cabeça é como fazer um objeto atrair o outro. Como vamos fazer esses dois objetos falarem um com o outro?Há várias maneiras de se fazer isso. Aqui estão apenas algumas possibilidades.
Tarefa | Função |
---|---|
1. Uma função que recebe um Attractor e um Mover : | attraction(a, m); |
2. Um método no objeto Attractor que recebe um Mover : | a.attract(m); |
3. Um método no objeto Mover que recebe um Attractor : | mover.attractedTo(a); |
4. Um método no objeto Attractor que recebe um Mover e retorna um PVector , que é a força de atração. Essa força de atração é então passada para o método applyForce() do objeto Mover . | `var f = a.calculateAttraction(m); |
mover.applyForce(f);` |
É bom olhar para um conjunto de opções para fazer os objetos conversarem uns com os outros e você pode provavelmente achar argumentos para cada uma das possibilidades acima. Vamos começar descartando o primeiro, uma vez que uma abordagem orientada a objetos é realmente uma escolha bem melhor do que uma função arbitrária não ligada aos objetos
Mover
ou Attractor
. Escolher a opção 2 ou 3 é a diferença entre dizer "O attractor atrai o Mover" ou "O Mover é atraído pelo attractor". O número 4 parece mais apropriado, pelo menos em termos de onde nós estamos neste curso. Afinal, nós gastamos bastante tempo trabalhando no método applyForce()
e eu acho que nossos exemplos serão mais claros se nós continuarmos com a mesma metodologia.Em outras palavras, onde tínhamos:
var f = new PVector(0.1, 0); // Força inventada
mover.applyForce(f);
Agora teremos:
var f = a.calculateAttraction(m); // Força de atração entre dois objetos
mover.applyForce(f);
Assim, nossa função
draw()
pode ser escrita como:draw = function() {
background(50, 50, 50);
// Calcula a força de atração e a aplica
var f = a.calculateAttraction(m);
mover.applyForce(f);
attractor.display();
mover.update();
mover.display();
};
Estamos quase lá. Uma vez que decidimos colocar o método
calculateAttraction()
dentro do objeto do tipo Attractor
, nós precisaremos escrever essa função. A função precisa receber um objeto Mover
e retornar um PVector. E o que há dentro dessa função? Toda aquela agradável matemática que nós resolvemos para a atração gravitacional!Attractor.prototype.calculateAttraction = function(mover) {
// Qual é a direção da força?
var force = PVector.sub(this.position, mover.position);
var distance = force.mag();
force.normalize();
// Qual é a magnitude da força?
var strength = (this.G * this.mass * mover.mass) / (distance * distance);
force.mult(strength);
// Retornar a força para que ela possa ser aplicada!
return force;
};
E nós acabamos. De certa forma. Quase. Há uma pequena questão que precisamos resolver. Vamos olhar novamente o código acima. Percebe aquele símbolo de divisão, a barra? Sempre que temos um desses, precisamos nos perguntar: O que aconteceria se a distância fosse um número realmente, realmente pequeno ou (pior ainda!) zero??! Bem, nós sabemos que não podemos dividir um número por 0, e se nós dividíssemos um número por alguma coisa como 0,0001, isso seria o equivalente a multiplicar esse número 10.000! Sim, esta é a equação do mundo real para a força da gravidade, mas nós não vivemos em um mundo real. Nós vivemos no mundo ProcessingJS. E no mundo ProcessingJS, o Mover poderia terminar ficando muito, muito perto do Attractor e a força poderia se tornar tão forte que o Mover iria simplesmente voar para fora da tela. Então, com esta fórmula, é bom sermos práticos e restringir o intervalo de valores que a distância pode ter. Talvez, não importa onde o
Mover
realmente está, nós nunca devemos considerá-lo a menos de 5 pixels ou mais que 25 pixels de distância do Attractor.distance = constrain(distance, 5, 25);
Pela mesma razão que nós precisamos restringir a distância mínima, é útil para nós fazer a mesma coisa com a máxima. Afinal, se o mover estivesse, digamos, a 500 pixels do attractor (o que não é absurdo), estaríamos dividindo a força por 250.000. Essa força poderia acabar sendo tão fraca que é quase como se ela não estivesse sendo aplicada.
Agora, é você quem realmente decide qual modo de funcionamento você quer. Mas no caso de, “Eu quero uma atração que pareça razoável, que nunca seja absurdamente fraca ou forte,” então restringir a distância é uma boa técnica.
Vamos agora reunir tudo em um programa. O objeto do tipo
Mover
não mudou nada, mas agora nosso programa inclui um objeto Attractor
e o código que os une. Também adicionamos código no programa para controlar o attractor com o mouse, de modo que seja mais fácil observar os efeitos.Mover
a aceitar massa, x, e y (como fizemos anteriormente), inicializar um array de Mover
s aleatoriamente posicionados, e percorrer o array para calcular a força de atração em cada um deles, um por vez:var movers = [];
var attractor = new Attractor();
for (var i = 0; i < 10; i++) {
movers[i] = new Mover(random(0.1, 2), random(width), random(height));
}
draw = function() {
background(50, 50, 50);
attractor.display();
for (var i = 0; i < movers.length; i++) {
var force = attractor.calculateAttraction(movers[i]);
movers[i].applyForce(force);
movers[i].update();
movers[i].display();
}
};
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?
Nenhuma postagem por enquanto.