273 votes

Balle pour Balle de Détection de Collision et de Manutention

Avec l'aide de la Pile de Dépassement de la communauté, j'ai écrit un assez basique mais plaisir physique du simulateur.

alt text

Vous cliquez et faites glisser la souris pour lancer une balle. Il va rebondir autour et finissent par s'arrêter sur le "plancher".

Ma prochaine grande fonctionnalité, je veux ajouter dans l'est de la balle pour balle de collision. Le mouvement de la balle est divisée en x et y vecteur vitesse. J'ai de la gravité (faible réduction de la y vecteur à chaque étape), j'ai frottement (petite réduction de deux vecteurs de chaque collision avec un mur). Les boules honnêtement déplacer dans un réalisme surprenant.

Je suppose que ma question est en deux parties:

  1. Quelle est la meilleure méthode pour détecter la balle pour balle de collision?
    Dois-je juste avoir un O(n^2) boucle qui itère sur chaque ballon et vérifie chaque autre balle pour voir si c'est le rayon de chevauchements?
  2. Que les équations dois-je utiliser pour manipuler le ballon pour ballon de collisions? La physique 101
    Comment fait-il effet les deux boules de vitesse x/y les vecteurs? Quel est le sens les deux balles à la tête? Comment puis-je l'appliquer à chaque balle?

alt text

La manipulation de la détection de collision des "murs" et le vecteur résultant des modifications ont été facile, mais je vois plus de complications avec balle-boule de collisions. Avec des murs j'ai simplement eu à prendre le négatif de l'x ou y du vecteur et il serait aller dans la bonne direction. Avec les boules, je ne pense pas que c'est de cette façon.

Quelques précisions: pour des raisons de simplicité, je suis ok avec un parfaitement élastique de collision pour l'instant, tous mes couilles ont la même masse, mais je suis susceptible de changer dans le futur.

Dans le cas où quelqu'un est intéressé dans le fait de jouer avec le simulateur j'ai fait jusqu'à présent, j'ai téléchargé la source ici (EDIT: Vérifiez la mise à la source ci-dessous).


Edit: Ressources que j'ai trouvé utile

2d Boule de physique avec des vecteurs: 2-Dimensions des Collisions Sans la Trigonométrie.pdf
2d Boule de détection de collision exemple: Ajout de la Détection de Collision


Succès!

J'ai la boule de détection de collision et de travail sur la réponse aux grands!

Code:

La Détection De Collision:

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]);
        }
    }
}

Cela permettra de vérifier les collisions entre chaque ballon, mais ignorer redondant vérifie (si vous en avez pour vérifier si la bille 1 en collision avec la balle 2, alors vous n'avez pas besoin de vérifier si la bille 2 en collision avec le ballon 1. Aussi, il ignore la vérification des collisions avec lui-même).

Alors, dans ma boule de classe, j'ai mes collision() et resolveCollision() méthodes:

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.multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    ball.velocity = ball.velocity.subtract(impulse.multiply(im2));

}

Code Source: source Complet pour balle pour balle collider.
Binaire: binaire Compilé dans le cas où vous voulez juste essayer de rebondir des boules autour.

Si quelqu'un a des suggestions pour améliorer cette base de la physique du simulateur laissez-moi savoir! Une chose que j'ai encore à ajouter est le moment angulaire sorte que les balles roulent de façon plus réaliste. Toutes les autres suggestions? Laisser un commentaire!

121voto

Jay Conrod Points 12375

Afin de détecter si les deux boules s'entrechoquent, il suffit de vérifier si la distance entre leurs centres est inférieur à deux fois le rayon. Pour faire un parfaitement élastique de collision entre les balles, vous avez seulement besoin de s'inquiéter à propos de la composante de la vitesse qui est dans la direction de la collision. Les autres composants (tangente à la collision) restera le même pour les deux balles. Vous pouvez obtenir la collision des composants par la création d'un vecteur unitaire dans la direction d'une balle à l'autre, en prenant le produit scalaire avec les vecteurs de la vitesse des balles. Vous pouvez ensuite brancher ces composants dans un 1D parfaitement élastique collision équation.

Wikipédia a un assez bon résumé de l'ensemble du processus. Pour les balles de masse, la nouvelle vitesses peuvent être calculés en utilisant les équations (où v1, v2 sont les vitesses après la collision, et u1, u2 sont d'avant):

v_{1} = \frac{u_{1}(m_{1}-m_{2})+2m_{2}u_{2}}{m_{1}+m_{2}}v_{2} = \frac{u_{2}(m_{2}-m_{1})+2m_{1}u_{1}}{m_{1}+m_{2}}

Si les boules ont la même masse puis les vitesses sont tout simplement changé. Voici un code que j'ai écrit qui fait quelque chose de similaire:

void Simulation::collide(Storage::Iterator a, Storage::Iterator b)
{
    // Check whether there actually was a collision
    if (a == b)
        return;

    Vector collision = a.position() - b.position();
    double distance = collision.length();
    if (distance == 0.0) {              // hack to avoid div by zero
        collision = Vector(1.0, 0.0);
        distance = 1.0;
    }
    if (distance > 1.0)
        return;

    // Get the components of the velocity vectors which are parallel to the collision.
    // The perpendicular component remains the same for both fish
    collision = collision / distance;
    double aci = a.velocity().dot(collision);
    double bci = b.velocity().dot(collision);

    // Solve for the new velocities using the 1-dimensional elastic collision equations.
    // Turns out it's really simple when the masses are the same.
    double acf = bci;
    double bcf = aci;

    // Replace the collision velocity components with the new ones
    a.velocity() += (acf - aci) * collision;
    b.velocity() += (bcf - bci) * collision;
}

Comme pour l'efficacité, Ryan Fox est à droite, vous devriez envisager de diviser la région en sections, puis de faire de la détection de collision à l'intérieur de chaque section. Gardez à l'esprit que les balles peuvent entrer en collision avec d'autres boules à l'intérieur d'une section, ce qui peut rendre votre code plus compliqué. L'efficacité ne sera probablement pas d'importance jusqu'à ce que vous avez plusieurs centaines de balles. Pour les points de bonus, vous pouvez exécuter chaque section sur une autre base, ou de diviser le traitement des collisions à l'intérieur de chaque section.

49voto

avp Points 2649

Eh bien, il y a des années j'ai fait le programme comme vous l'avez présenté ici.
Il y a un problème caché (ou plusieurs, dépend du point de vue):

  • Si la vitesse de la balle est trop haut, vous ne pouvez rater la collision.

Et aussi, presque 100% des cas, votre nouvelle vitesses sera mauvais. Eh bien, pas de vitesses, mais les positions. Vous devez calculer les vitesses précisément au bon endroit. Sinon vous suffit de changement de balles, à une petite "erreur", qui est disponible à partir de la précédente discret étape.

La solution est évidente: il faut diviser le timestep donc, que d'abord vous déplacer à la bonne place, puis entrent en collision, puis changement pour le reste du temps dont vous disposez.

20voto

grepsedawk Points 3413

Vous devriez utiliser le partitionnement de l'espace pour résoudre ce problème.

Lire sur Binaire Partitionnement De L'Espace et Quadtrees

13voto

Andrew Rollings Points 8361

Une clarification de la proposition de Ryan Fox de diviser l'écran en régions, et la seule vérification pour les collisions dans les régions...

par exemple, diviser l'aire de jeu dans une grille de carrés (qui sera arbitrairement dire sont de 1 unité de longueur de chaque côté), et de vérifier les collisions à l'intérieur de chaque carré de la grille.

C'est absolument la bonne solution. Le seul problème avec elle (comme une autre affiche a souligné est que les collisions au-delà des frontières sont un problème.

La solution à cela est de superposer une deuxième grille, à 0,5 unité verticale et horizontale de décalage à la première.

Ensuite, les collisions qui serait au-delà des frontières dans la première grille (et donc ne pas détectée) sera dans les cases de la grille dans la deuxième grille. Tant que vous garder une trace de la collision, vous avez déjà géré (comme il est probable que certains se chevauchent), vous n'avez pas à vous inquiéter au sujet de la manipulation des cas limites. Tous les collisions seront à l'intérieur d'un carré de la grille sur l'une des grilles.

10voto

Ryan Fox Points 5181

Un bon moyen de réduire le nombre de tests de collision est de diviser l'écran en différentes sections. Il suffit alors de comparer chaque balle les couilles dans la même section.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X