Com a ajuda da comunidade Stack Overflow, escrevi um simulador de física bastante básico, mas divertido.
Você clica e arrasta o mouse para lançar uma bola. Ele vai ricochetear e eventualmente parar no "chão".
Meu próximo grande recurso que quero adicionar é colisão bola a bola. O movimento da bola é dividido em machado e vetor de velocidade y. Tenho gravidade (pequena redução do vetor y a cada passo), tenho atrito (pequena redução dos dois vetores a cada colisão com uma parede). As bolas se movem honestamente de uma maneira surpreendentemente realista.
Eu acho que minha pergunta tem duas partes:
- Qual é o melhor método para detectar colisão de bola em bola?
Eu só tenho um loop O (n ^ 2) que itera sobre cada bola e verifica todas as outras bolas para ver se o raio se sobrepõe? - Que equações eu uso para lidar com a bola em colisões? Física 101
Como isso afeta as duas bolas na velocidade dos vetores x / y? Qual é a direção resultante em que as duas bolas seguem? Como aplico isso a cada bola?
Lidar com a detecção de colisão das "paredes" e as alterações vetoriais resultantes foi fácil, mas vejo mais complicações com colisões bola-bola. Com paredes, eu simplesmente tive que pegar o negativo do vetor x ou y apropriado e ele seguiria na direção correta. Com bolas, não acho que seja assim.
Alguns esclarecimentos rápidos: por simplicidade, estou bem com uma colisão perfeitamente elástica no momento, também todas as minhas bolas têm a mesma massa agora, mas posso mudar isso no futuro.
Edit: Recursos que achei úteis
Física da 2d Ball com vetores: Colisões bidimensionais sem trigonometria.pdf
Exemplo de detecção de colisão da 2d Ball: Adicionando detecção de colisão
Sucesso!
Tenho a detecção e resposta de colisão de bola funcionando muito bem!
Código relevante:
Detecção de colisão:
for (int i = 0; i < ballCount; i++)
{
for (int j = i + 1; j < ballCount; j++)
{
if (balls[i].colliding(balls[j]))
{
balls[i].resolveCollision(balls[j]);
}
}
}
Isso verificará colisões entre todas as bolas, mas ignorará verificações redundantes (se você precisar verificar se a bola 1 colide com a bola 2, não será necessário verificar se a bola 2 colide com a bola 1. Além disso, ignora a verificação de colisões consigo mesma )
Então, na minha classe de bola, tenho meus métodos colliding () e resolveCollision ():
public boolean colliding(Ball ball)
{
float xd = position.getX() - ball.position.getX();
float yd = position.getY() - ball.position.getY();
float sumRadius = getRadius() + ball.getRadius();
float sqrRadius = sumRadius * sumRadius;
float distSqr = (xd * xd) + (yd * yd);
if (distSqr <= sqrRadius)
{
return true;
}
return false;
}
public void resolveCollision(Ball ball)
{
// get the mtd
Vector2d delta = (position.subtract(ball.position));
float d = delta.getLength();
// minimum translation distance to push balls apart after intersecting
Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / ball.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));
// impact speed
Vector2d v = (this.velocity.subtract(ball.velocity));
float vn = v.dot(mtd.normalize());
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse
float i = (-(1.0f + Constants.restitution) * vn) / (im1 + im2);
Vector2d impulse = mtd.normalize().multiply(i);
// change in momentum
this.velocity = this.velocity.add(impulse.multiply(im1));
ball.velocity = ball.velocity.subtract(impulse.multiply(im2));
}
Código Fonte: Fonte completa para o colisor de bola em bola.
Se alguém tiver alguma sugestão de como melhorar este simulador básico de física, avise-me! Uma coisa que ainda tenho que acrescentar é o momento angular, para que as bolas rolem mais realisticamente. Alguma outra sugestão? Deixe um comentário!
Vector2d impulse = mtd.multiply(i);
deve ser * o vetor mtd normalizado. Algo como:Vector2d impulse = mtd.normalize().multiply(i);