2010-07-12 10 views
5

Je dois faire un algorithme qui détecte quand deux sphères entrent en collision, et, la direction que l'on prendra un instant après la collision. Disons, Imaginez que lorsque vous ouvrez votre table dans un match de poule, toutes les balles entrent en collision les unes avec les autres "au hasard". Donc, avant de commencer à écrire moi-même le code, je pensais qu'il existait déjà une implémentation de ce code là-bas.Sphère - détection de collision de sphère -> réaction

Merci d'avance!

Cyas.-

+0

La partie la plus difficile est le spin ... –

+0

Je ne me soucie pas de la rotation, j'ai seulement besoin de colissions et de "réactions plates". – Artemix

+0

La direction est simplement le long de la ligne reliant les centres. – Mau

Répondre

7

Vous pouvez trouver un bon tutoriel ici: Link

+0

Bien sûr que ça va l'homme, merci. Mais, je n'ai pas besoin de collision en 3D, je voulais dire en fait une collection de cercles - pas de sphères du tout: p ma mauvaise. – Artemix

+0

@Artemix: Si vous regardez cette page, il semble que ce soit la plupart des explications en 2D! +1 pour un bel article. –

+0

Oui, j'ai remarqué cela. – Artemix

7

La partie collision est facile. Vérifiez si la distance entre les centres des sphères est inférieure à la somme de leur rayon. En ce qui concerne le rebond, vous devez permuter les quantités de vélocité qui contribuent à la vitesse totale perpendiculaire à la collision des sphères. (En supposant que toutes vos sphères ont une masse égale, ce serait différent pour une combinaison de différentes masses)

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 vous avez besoin plus de précision, puis sur une collision, vous devez calculer la distance pour déplacer les deux sphères qui entrent en collision vers l'arrière afin qu'ils se touchent, puis déclencher la fonction de collision. Cela assurerait que les angles seront plus précis.

+0

Fonctionne bien - mais je pense qu'il y a un problème: je commence avec 10 balles (sans chevauchement), où une seule a de la vélocité - après un petit moment et beaucoup de rebondissements, elles bougent toutes. À l'intervalle, je résume toutes les vitesses (abs (x) + abs (y)) - si j'ai commencé avec, disons 8 en tout, ça grandit rapidement (ce qui doit violer l'une des lois de conservation?) Mais après un certain temps cesse de croître, fluctue autour de 20 .. Je suis confus et je ne sais pas si je devrais être .. (Note: après la détection d'une collision je déplace la première balle vers l'arrière, en quelques minutes, jusqu'à ce qu'elles ne se chevauchent plus avant d'appeler performCollision – T4NK3R

+0

Essayez de résumer (sqrt (vx^2 + vy^2)) pour chacun. – clinux