Petite astuce Détection de collision entre un cercle et une ligne

Dans mon précédent Quick Tip, nous avions examiné la détection de collision en général, et plus particulièrement la détection de collisions entre deux cercles. Dans cette astuce, nous allons détecter une collision entre un cercle et une ligne.


C'est le résultat sur lequel nous allons travailler. Cliquez sur le bouton Redémarrer pour repositionner tous les cercles en haut de la scène et les regarder tomber.

Notez que les cercles entrent en collision avec la ligne même en dehors du segment tracé. Mon prochain conseil rapide montrera comment résoudre ce problème.


Étape 1: L'idée générale

Pour vérifier si un cercle est entré en collision avec une ligne, nous devons vérifier la longueur perpendiculaire de la ligne au cercle. Observez le schéma ci-dessous.

Le diagramme ci-dessus montre clairement que les cas 3 et 4 devraient détecter une collision entre le cercle et la ligne. Nous concluons donc que si la longueur perpendiculaire (marquée en rouge) est égale ou inférieure au rayon du cercle, une collision est survenue du fait que le cercle a touché ou recouvert la ligne. La question est de savoir comment calculer cette longueur perpendiculaire. Eh bien, les vecteurs peuvent aider à simplifier notre problème.


Étape 2: Ligne normale

Pour tracer une ligne sur scène, nous avons besoin de deux coordonnées (c1 et c2). La ligne tracée de c1 à c2 formera un vecteur pointant vers c2 (notez le sens de la flèche).

Ensuite, nous devons trouver la ligne Ordinaire. La ligne normale est une autre ligne qui fait 90 ° avec la ligne d'origine et la croise en un point. Bien que la ligne soit normale, la forme vectorielle de la normale peut encore être identifiée comme étant la ligne. la gauche ou droite normal par rapport au vecteur de la ligne. La normale gauche est le vecteur de ligne lui-même, tourné à -90 °. La droite normale est la même, mais pivotée de 90 °. N'oubliez pas que l'axe des y dans l'espace de coordonnées de Flash est inversé par rapport à l'axe des y d'un graphique typique: la rotation positive est donc dans le sens des aiguilles d'une montre et la rotation négative dans le sens contraire des aiguilles d'une montre..


Étape 3: Projection à gauche normale

La normale gauche est utilisée dans notre tentative de calculer la longueur perpendiculaire entre le cercle et la ligne. Les détails peuvent être trouvés dans le diagramme ci-dessous. UNE fait référence à un vecteur pointant de c1 au cercle. La longueur perpendiculaire fait en fait référence au vecteur A projection à gauche normal. Nous dérivons cette projection en utilisant la trigonométrie: c'est | A | Cosinus (thêta), où | A | fait référence à la magnitude du vecteur UNE.

L’approche la plus simple consiste à utiliser des opérations vectorielles, en particulier le produit scalaire. En partant de l'équation du produit scalaire, nous réorganisons les termes pour arriver à la deuxième expression ci-dessous. Notez que le côté droit de la deuxième équation est la projection que nous voulions calculer!

Notez également que les côtés gauche et droit de l'équation produiront le même résultat, bien que leurs approches soient différentes. Ainsi, au lieu d'utiliser le côté droit de l'équation, nous pouvons opter pour le côté gauche de l'équation. Pour arriver facilement au résultat final, il est avantageux d’utiliser la gauche car les variables peuvent être facilement résolues. Si nous insistons pour utiliser le droit d’équation, il nous faudra pousser ActionScript dans un travail mathématique rigoureux pour calculer l’angle thêta. Nous concluons avec le schéma ci-dessous.

(* Remarque supplémentaire: si le cercle tombe sous le vecteur ligne, la longueur perpendiculaire calculée à partir de la formule du diagramme ci-dessus produira une valeur négative.)


Étape 4: Implémentation de la détection de collision cercle-ligne

Maintenant que nous avons compris l'approche mathématiquement, passons à l'implémenter dans ActionScript. Dans cette première section, notez que le vecteur de la ligne subit une rotation de -90 ° pour former la normale gauche..

 // déclaration des coordonnées x1 = 50; y1 = 100; x2 = 250; y2 = 150; // ligne de dessin graphics.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // formant des vecteurs de ligne line = nouveau Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0.5);

Dans cette deuxième section, j’ai mis en évidence les calculs mentionnés et la condition permettant de vérifier la collision entre le cercle et la ligne..

 rafraîchissement de fonction privée (e: événement): void pour (var i: int = 0; i < circles.length; i++)  //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); circles[i].y += 2; //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius) circles[i].y -= 2;   

Pour ceux qui souhaitent approfondir leurs recherches, voici quelques extraits de méthodes utilisées dans Vector.as

 / ** * Méthode permettant d'obtenir la projection du vecteur en cours sur un axe donné * @param axis Un axe où le vecteur est projeté en * @return La longueur de projection du vecteur en cours sur un axe donné * / fonction publique projectionOn (axe: Vector2D): Number return this.dotProduct (axis.normalise ())
 / ** * Méthode permettant d'exécuter un produit scalaire avec un autre vecteur * @param vector2 Un vecteur permettant d'exécuter un produit scalaire avec le vecteur en cours * @return Un nombre scalaire de produit scalaire * / fonction publique dotProduct (vector2: Vector2D): Number var composantX: Nombre = this._vecX * vector2.x; var composantY: Nombre = this._vecY * vector2.y; renvoyer composantX + composantY; 
 / ** * Méthode permettant d'obtenir l'unité vectorielle du vecteur actuel * @return Une copie du vecteur normalisé * / public function normalize (): Vector2D renvoie le nouveau vecteur Vector2D (this._vecX / this.getMagnitude (), this._vecY / this. getMagnitude ())
 / ** * Méthode permettant d'obtenir la magnitude actuelle du vecteur * @return Magnitude de type Number * / fonction publique getMagnitude (): Number return Math.sqrt (_vecX * _vecX + _vecY * _vecY); 

Étape 5: le résultat

Appuyez sur le bouton Redémarrer pour repositionner tous les cercles en haut de la scène. Notez que la collision est entre le entier ligne (y compris la section non dessinée) et les cercles. Afin de limiter les collisions au segment de ligne uniquement, restez à l'écoute pour le prochain conseil rapide.

Conclusion

Merci d'avoir lu. Restez à l'écoute pour le prochain conseil.