2010-07-12 24 views
5

Necesito hacer un algoritmo que detecte cuando dos esferas colisionan, y, la dirección que tomará un instante después de la colisión.Esfera - esfera detección de colisión -> reacción

Supongamos que cuando abres la mesa en un partido de piscina, todas las bolas chocan entre sí "aleatoriamente".

Entonces, antes de comenzar a escribir el código yo mismo, estaba pensando si ya hay una implementación de esto por ahí.

¡Thx por adelantado!

Cyas.-

+0

La parte más difícil es la rotación ... –

+0

No me importa el giro, solo necesito colisiones y "reacciones planas". – Artemix

+0

La dirección es simplemente a lo largo de la línea que conecta los centros. – Mau

Respuesta

7

Puede encontrar un buen tutorial aquí: Link

+0

Claro que lo hará el hombre, gracias. Pero, no necesito una colisión en 3D, me refiero a la colisión del círculo circular en realidad, no a las esferas en absoluto: p mi mal. – Artemix

+0

@Artemix: ¡Si miras esa página, parece estar haciendo la mayor parte de la explicación en 2D! +1 por buen artículo. –

+0

Sí, me di cuenta de eso. – Artemix

7

La colisión parte es fácil. Verifica si la distancia entre los centros de esferas es menor que la suma de su radio.

En cuanto al rebote, debe intercambiar las cantidades de velocidad que contribuyen a la velocidad total perpendicular a la colisión de las esferas. (Suponiendo que todas sus esferas tienen la misma masa, que sería diferente de una combinación de diferentes masas)

struct Vec3 { 
    double x, y, z; 
} 

Vec3 minus(const Vec3& v1, const Vec3& v2) { 
    Vec3 r; 
    r.x = v1.x - v2.x; 
    r.y = v1.y - v2.y; 
    r.z = v1.z - v2.z; 
    return r; 
} 

double dotProduct(const Vec3& v1, const Vec3& v2) { 
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 
} 

Vec3 scale(const Vec3& v, double a) { 
    Vec3 r; 
    r.x = v.x * a; 
    r.y = v.y * a; 
    r.z = v.z * a; 
    return r; 
} 

Vec3 projectUonV(const Vec3& u, const Vec3& v) { 
    Vec3 r; 
    r = scale(v, dotProduct(u, v)/dotProduct(v, v)); 
    return r; 
} 

int distanceSquared(const Vec3& v1, const Vec3& v2) { 
    Vec3 delta = minus(v2, v1); 
    return dotProduct(delta, delta); 
} 

struct Sphere { 
    Vec3 position; 
    Vec3 velocity; 
    int radius; 
} 

bool doesItCollide(const Sphere& s1, const Sphere& s2) { 
    int rSquared = s1.radius + s2.radius; 
    rSquared *= rSquared; 
    return distanceSquared(s1.position, s2.position) < rSquared; 
} 

void performCollision(Sphere& s1, Sphere& s2) { 
    Vec3 nv1; // new velocity for sphere 1 
    Vec3 nv2; // new velocity for sphere 2 
    // this can probably be optimised a bit, but it basically swaps the velocity amounts 
    // that are perpendicular to the surface of the collistion. 
    // If the spheres had different masses, then u would need to scale the amounts of 
    // velocities exchanged inversely proportional to their masses. 
    nv1 = s1.velocity; 
    nv1 += projectUonV(s2.velocity, minus(s2.position, s1.position)); 
    nv1 -= projectUonV(s1.velocity, minus(s1.position, s2.position)); 
    nv2 = s2.velocity; 
    nv2 += projectUonV(s1.velocity, minus(s2.position, s1.position)); 
    nv2 -= projectUonV(s2.velocity, minus(s1.position, s2.position)); 
    s1.velocity = nv1; 
    s2.velocity = nv2; 
} 

EDIT: Si necesita más precisión, a continuación, tras una colisión debe calcular qué tan lejos se mueva tanto en el ámbito que chocan hacia atrás para que solo se toquen entre sí, luego activen la función de colisión de ejecución. Eso aseguraría que los ángulos sean más precisos.

+0

Funciona muy bien, pero creo que hay un problema: comienzo con 10 bolas (ninguna superpuesta), donde solo una tiene velocidad: después de un momento y rebotando, todas se mueven. A intervalos resumí todas las velocidades (abs (x) + abs (y)) - si comencé con, digamos 8 en total, crece rápidamente (¿qué debe violar una de las leyes de conservación?) Pero después de un tiempo deja de crecer, solo fluctúa alrededor de 20 ... Estoy confundido Y no estoy seguro de si debería ser ... (Nota: después de detectar una colisión muevo la primera bola hacia atrás, en pasos de un minuto, hasta que ya no se superponen, antes de llamar a performCollision) – T4NK3R

+0

Intente resumir (sqrt (vx^2 + vy^2)) para cada uno. – clinux

Cuestiones relacionadas