2010-07-12 3 views
5

Ho bisogno di fare un algoritmo che rileva quando due sfere si scontrano, e, la direzione che uno prenderà un istante dopo la collisione.Rilevamento sfera - sfera di collisione -> reazione

Diciamo, immagina come quando apri il tuo tavolo in una partita di biliardo, tutte le palle si scontrano l'una con l'altra "a caso".

Quindi, prima di iniziare a scrivere il codice da solo, stavo pensando se c'è già una implementazione di questo là fuori.

Thx in anticipo!

Cyas.-

+0

La parte più difficile è lo spin ... –

+0

Non mi interessa la rotazione, ho solo bisogno di colli e "reazioni piatte". – Artemix

+0

La direzione è semplicemente lungo la linea che collega i centri. – Mau

risposta

7

È possibile trovare un buon tutorial qui: Link

+0

Certo che sarà uomo, grazie. Ma, non ho bisogno di collisione 3D, intendevo davvero la collisione cerchio-cerchio, non le sfere affatto: p mio male. – Artemix

+0

@Artemix: se guardi quella pagina, sembra che stia facendo la maggior parte delle spiegazioni in 2D! +1 per un bell'articolo. –

+0

Sì, l'ho notato. – Artemix

7

La collisione parte è facile. Controllare se la distanza tra i centri delle sfere è inferiore alla somma del loro raggio.

Come per il rimbalzo, è necessario scambiare le quantità di velocità che contribuiscono alla velocità totale perpendicolare alla collisione delle sfere. (Supponendo che tutte le sfere hanno massa uguale, sarebbe diverso per una combinazione di diverse masse)

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: Se avete bisogno di una maggiore precisione, poi su di una collisione si dovrebbe calcolare quanto lontano per spostare entrambe le sfere in collisione all'indietro in modo che si tocchino l'un l'altro, quindi attivano la funzione di collisione. Ciò assicurerebbe che gli angoli saranno più precisi.

+0

Funziona alla grande - ma penso che ci sia un problema: comincio con 10 palle (nessuna sovrapposta), dove solo una ha velocità - dopo un po 'di tempo e un sacco di rimbalzi si muovono tutti. A intervalli riassumo tutte le velocità (abs (x) + abs (y)) - se ho iniziato con, diciamo 8 in tutto, cresce rapidamente (che deve violare una delle leggi di conservazione?) Ma dopo un po ' smette di crescere, solo fluttua intorno ai 20 .. Sono confuso E non sono sicuro se dovrei essere .. (Nota: dopo che una collisione è stata rilevata, sposto la prima pallina all'indietro, in pochi minuti, finché non si sovrappongono più, prima di chiamare performCollision) – T4NK3R

+0

Prova a sommare (sqrt (vx^2 + vy^2)) per ciascuno. – clinux