un algorithme de collision rectangle 2D simple qui détermine également de quels côtés les rectangles entrent en collision?

16

J'ai d'abord essayé d'implémenter l'intersection rectangulaire, qui fonctionne bien. Cependant, lorsque je dois appliquer le système physique, comme la vitesse, l'accélération et les vecteurs directionnels, je dois trouver un moyen de déterminer de quel côté des rectangles entrent en collision. Maintenant, dans mon système, il n'y a pas de rectangle tourné, donc cela a simplifié le problème. Cependant, je n'ai pas pu trouver un moyen facile de déterminer quel côté rectangle est entré en collision. J'ai déjà traité ce problème auparavant, mais j'ai lamentablement échoué.

Ce que j'ai fait dans le passé, c'est de déterminer la distance entre chaque côté rectangulaire parallèle et de vérifier si la distance est proche de 0 (utilisez une plage de distance initialement définie) ou est 0. Cependant, pour l'arithmétique à virgule flottante, cela s'avère instable car de temps inconnu. Parfois, les rectangles se coupent réellement avant de rencontrer la plage définie.

D'un autre côté, je pensais à créer plusieurs rectangles, chaque rectangle pour chaque côté. Cependant, après avoir repensé, ce serait la même chose que d'avoir un côté parallèle avec vérification de la plage de distance, juste que cette plage de distance est la largeur de chaque mini-rectangle.

Par conséquent, une suggestion à ce problème?

user1542
la source
Utilisez-vous des mises à jour de position discrètes ou continues? (mettez-vous à jour votre vitesse par l'accélération une fois par image puis calculez-vous la position, ou utilisez-vous une fonction pour extrapoler la position)
Casey Kuball

Réponses:

24

Adapté de ma réponse à "De quel côté a été touché?" :

Je suggère de calculer la somme de Minkowski de B et A, qui est un nouveau rectangle, et de vérifier où se situe le centre du rectangle A par rapport à ce nouveau rectangle (pour savoir si une collision se produit) et à ses diagonales (pour savoir la collision est passe):

float w = 0.5 * (A.width() + B.width());
float h = 0.5 * (A.height() + B.height());
float dx = A.centerX() - B.centerX();
float dy = A.centerY() - B.centerY();

if (abs(dx) <= w && abs(dy) <= h)
{
    /* collision! */
    float wy = w * dy;
    float hx = h * dx;

    if (wy > hx)
        if (wy > -hx)
            /* collision at the top */
        else
            /* on the left */
    else
        if (wy > -hx)
            /* on the right */
        else
            /* at the bottom */
}
sam hocevar
la source
1
Je voudrais ajouter que «haut» et «bas» sont relatifs à votre système de coordonnées. Dans mon jeu par exemple, (0,0) est en haut à gauche, donc ils sont inversés par rapport à votre exemple. Juste quelque chose à garder à l'esprit.
Neikos
excellente solution, a très bien fonctionné pour mes besoins.
Opiatefuchs
1
Y a-t-il un problème avec dx devenant 0 ou dy devenant 0 ou les deux? Permettez-moi de le raisonner ... si dx = 0 && dy == 0, cela signifie que les deux rectangles sont de la même origine, alors l'algorithme renvoie le bas par défaut? si l'un d'eux vaut 0, le résultat correct est attendu. Donc, je pense que cet algorithme est correct, sauf dans le cas où dx == 0 && dy == 0, qui devrait être indéterminé et non inférieur. Alors, méfiez-vous et merci.
Prasanth
1
Maintenant, je me demandais ce qui se passe lorsque dx == dy, w == h ... alors aussi, le code décide que le résultat est d'un côté alors qu'il est en réalité indéterminé..imaginez deux carrés se croisant de telle sorte que le centre d'un carré est à un coin d'un autre carré et le centre de l'autre carré est au coin du premier carré. Ici, le côté doit être indéterminé - ce n'est ni à droite ni en bas. C'est les deux?!
Prasanth