Con la ayuda de la comunidad Stack Overflow, he escrito un simulador de física bastante básico pero divertido.
Hace clic y arrastra el mouse para lanzar una pelota. Saltará y finalmente se detendrá en el "piso".
Mi próxima gran característica que quiero agregar es la colisión bola a bola. El movimiento de la pelota se divide en hacha y vector de velocidad. Tengo gravedad (pequeña reducción del vector y en cada paso), tengo fricción (pequeña reducción de ambos vectores cada colisión con una pared). Las bolas se mueven honestamente de una manera sorprendentemente realista.
Supongo que mi pregunta tiene dos partes:
- ¿Cuál es el mejor método para detectar la colisión de bola a bola?
¿Solo tengo un bucle O (n ^ 2) que itera sobre cada bola y comprueba cada otra bola para ver si se superpone el radio? - ¿Qué ecuaciones utilizo para manejar las colisiones entre bolas? Física 101
¿Cómo afecta a los vectores de velocidad x / y de dos bolas? ¿En qué dirección se dirigen las dos bolas? ¿Cómo aplico esto a cada bola?
Manejar la detección de colisiones de las "paredes" y los cambios de vectores resultantes fueron fáciles, pero veo más complicaciones con las colisiones de bolas. Con los muros, simplemente tenía que tomar el negativo del vector x o y apropiado y partirlo iría en la dirección correcta. Con las bolas no creo que sea así.
Algunas aclaraciones rápidas: por simplicidad, estoy bien con una colisión perfectamente elástica por ahora, también todas mis bolas tienen la misma masa en este momento, pero podría cambiar eso en el futuro.
Editar: recursos que he encontrado útiles
Física de la bola 2D con vectores: colisiones bidimensionales sin trigonometría.pdf
Ejemplo de detección de colisión de bola 2D: adición de detección de colisión
¡Éxito!
¡Tengo la detección y respuesta de colisión de bolas funcionando muy bien!
Código relevante:
Detección de colisiones:
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]);
}
}
}
Esto verificará si hay colisiones entre cada bola, pero omite las verificaciones redundantes (si tiene que verificar si la bola 1 colisiona con la bola 2, entonces no necesita verificar si la bola 2 colisiona con la bola 1. Además, omite la comprobación de colisiones consigo mismo )
Luego, en mi clase de pelota tengo mis métodos colliding () y 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 fuente: fuente completa para el colisionador bola a bola.
Si alguien tiene algunas sugerencias sobre cómo mejorar este simulador de física básica, ¡hágamelo saber! Una cosa que aún tengo que agregar es el momento angular para que las bolas rueden de manera más realista. ¿Cualquier otra sugerencia? ¡Deja un comentario!
Vector2d impulse = mtd.multiply(i);
debe ser i * el vector mtd normalizado. Algo así como:Vector2d impulse = mtd.normalize().multiply(i);