Détection de collision avec courbes


12

Je travaille sur un jeu 2D dans lequel j'aimerais faire une détection de collision entre un cercle en mouvement et une sorte de courbes statiques (peut-être des courbes de Bézier).

Actuellement, mon jeu ne comporte que des lignes droites comme géométrie statique et je fais la détection de collision en calculant la distance du cercle aux lignes et en projetant le cercle hors de la ligne au cas où la distance serait inférieure au rayon des cercles.

Comment puis-je effectuer ce type de détection de collision d'une manière relativement simple? Je sais par exemple que Box2D propose une détection de collision avec des courbes de Bézier. Je n'ai pas besoin d'un mécanisme de détection de collision complet, juste quelque chose qui peut faire ce que j'ai décrit.


MISE À JOUR: Merci beaucoup pour les bonnes réponses! Je vais devoir lire sur les courbes de Bézier pour bien comprendre la méthode que vous avez décrite. Je reviendrai ensuite vers vous.

Réponses:


6

29/09/2012 - 23:20

J'ai créé un git Repo ici: https://github.com/ArthurWulfWhite/Bezier-Distance/

Vous pouvez télécharger les fichiers source sous forme de zip à partir de là. Il comprend également une démo que vous pouvez compiler à l'aide de FlashDevelop. Pour utiliser la démo, ouvrez le projet dans Flash Develop et cliquez sur 'Test Project'. Pendant l'exécution de la démo, cliquez sur le LMB pour randomiser une nouvelle courbe de Bézier et un nouveau cercle.

Bonne chance!

Le lien zip est difficile à voir - utilisez simplement Ctrl + F et tapez zip. Cette source représente quelques semaines de recherche et de programmation, j'espère qu'elle vous plaira.


Si vous prévoyez de diviser le bezier de manière récursive en segments et de vérifier les collisions avec eux, je suggère de créer un tableau de 100100 (grille) et de placer chaque segment dans les quatre carrés les plus proches, de sorte que vous n'avez qu'à vérifier les collisions avec 4/10 000 des segmente chaque image.

Je pense que vous bénéficierez de box2d à la fois en tant que programmeur et en tant que créateur de jeux, car il y a beaucoup de petits obstacles cachés dans la création d'un moteur physique `` simple '' qui rend le mouvement un peu cahoteux et moins fluide qu'il pourrait l'être.

Ancienne réponse: la voie pure.

Vous pouvez réellement voir si un cercle entre en collision avec une courbe de Bézier, en vérifiant la distance entre la distance entre le centre du cercle et le point le plus proche sur la courbe.

L'équation de la distance (en général)

expliqué:

Équation de Bézier:

q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Cela peut se résumer à (avec une algèbre) - je vais omettre. (X, y) pour plus de lisibilité (ce sont toujours des points, pas un nombre)

q(t) = (start -2 * cont + end) t^2 + (-2 * start + 2 * control) + start

La distance du point (x, y) est:

sqrt ((q(t).x - point.x)^2 + (q(t).y - point.y)^2)

Pour trouver le point le plus proche sur le bezier de la balle, vous devez dériver et trouver tous les points où la dérivée est égale à zéro (les racines). Il s'agit d'un polynôme du troisième degré, vous pouvez donc utiliser une formule fermée, mais il peut ne pas être fiable car la précision des fractions représentées par virgule flottante de l'ordinateur peut ne pas être suffisante. Il est préférable d'utiliser Newton ou quelque chose de ce genre.

Le dérivé dont vous avez besoin pour trouver les racines est:

En supposant: a = début b = contrôle c = fin d = point central de cercle

Dérivé utilisant wolfram alpha

La partie délicate consiste à multiplier ces points, vous devez utiliser le produit scalaire.

Si vous le souhaitez, j'ai le code pour cela et je peux le partager ici sous la forme d'une fonction qui renvoie simplement un booléen s'il y a ou non collision et un angle de collision. Certains problèmes pourraient apparaître dans la mise en œuvre naïve d'un moteur de collision comme celui-ci, par exemple une balle en mouvement rapide pourrait se coincer entre deux courbes.

Je recommande de l'éviter pour l'instant, résumez simplement les coefficients pour l'axe x et pour l'axe y et additionnez-les.

Utilisez n'importe quelle méthode fiable que vous pouvez choisir comme Newton pour trouver les racines, vérifiez la distance entre les points de racine sur le bezier, 0 <= t <= 1 au centre du cercle et vérifiez la distance pour les deux extrémités du bezier (commencez et fin) au centre du cercle, celui qui est le plus proche, vous dira s'il y a une collision.

Si le rayon est inférieur à la distance minimale, il y a collision.

L'angle est approximativement celui entre le centre du cercle et le point le plus proche sur le bezier.

Cela étant dit, si vous souhaitez vraiment faire un jeu avec la physique des collisions, je vous suggère de parcourir le bezier

    q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Divisez chaque pièce au milieu de manière récursive jusqu'à ce qu'elle soit suffisamment petite, disons 10 pixels ou moins, puis construisez grossièrement le bezier à partir de boîtes et utilisez Box2d pour la physique, car il est possible que l'écriture de tout ce code de détection de collision se révèle être une excellente un temps qui n'améliore pas beaucoup le gameplay. L'utilisation de Box2d a fait ses preuves dans d'innombrables projets dans le passé.


La méthode que vous décrivez pour calculer le point le plus court de la courbe est exactement celle que j'utilise actuellement avec des lignes au lieu de courbes. Mais faire de même pour les courbes avec la méthode que vous expliquez semble un peu trop compliqué. Si je comprends bien, c'est aussi ce que vous pensez. Et concernant Box2D. Je suis certain que c'est un excellent travail. Mais la physique dans mon jeu est honnêtement très simple et j'ai donc décidé qu'un moteur physique à part entière est exagéré.
paldepind

Combien d'objets y a-t-il dans votre jeu? Combien peuvent entrer en collision les uns avec les autres? Parfois, l'utilisation d'un moteur physique peut apporter de grands avantages, car il calcule avec précision le temps de collision. (car les images sont discrètes et les collisions sont réelles (ne se produisent pas précisément lorsque vous effectuez le rendu d'une image)
AturSams

Souvent, ce sont des défis inattendus lors de la mise en œuvre de quelque chose de nouveau et la beauté de l'utilisation d'une API physique 2d, c'est que c'est comme utiliser n'importe quel langage de programmation, cela ne nécessite pas d'effort particulier de votre part autre que d'investir quelques heures pour l'apprendre et les résultats sont très satisfaisants.
AturSams

J'ai ajouté quelques détails en ce moment, bonne chance. :)
AturSams

Je crée un jeu simple comme Elasto Mania. Seulement trois cercles en mouvement et géométrie statique. L'ensemble du moteur est terminé et fonctionne très bien. La seule chose qui reste est de permettre les courbes que je suis sur le point de résoudre grâce à l'aide de cette réponse :) N'hésitez pas à poster le code que vous avez mentionné. Dans quelle mesure pensez-vous qu'il serait approprié de l'utiliser dans la vie réelle? Mieux que de convertir le bezier en minuscules lignes?
paldepind

7

Pour ce faire, je voudrais:

  • Brisez la courbe de Bézier en plusieurs segments de ligne et stockez-les.

  • Placez tous ces segments dans un cadre de délimitation aligné sur l'axe pour toute la courbe.

Détection de collision :

1) Vérifiez si la sphère se trouve à l'intérieur du cadre de sélection principal. sinon, pas de collision.

2) sinon, vérifiez si l'un des segments individuels calculés ci-dessus entre en collision avec la sphère. Voir l' article sur l'intersection ligne-sphère de Wikipedia .

EDIT: si vous avez besoin d'une grande précision et que vous souhaitez de bonnes performances, vous pouvez également créer un cadre de délimitation principal pour toute la courbe, puis subdiviser la courbe en deux segments (par exemple: [0.0 - 0.5]et [0.5 - 1.0]). Créez une boîte boudante pour chacun d'eux, puis subdivisez à nouveau chacun de ces segments en deux segments (donnant ainsi [0 - 0.25], [0.25 - 0.5]et [0.5 - 0.75], [0.75 - 1.0]). Continuez ainsi jusqu'à ce que vous atteigniez suffisamment de précision. à la fin, vous aurez un binary treedes cadres de délimitation avec un cadre de délimitation de la courbe principale à la racine et des segments de ligne aux feuilles. la recherche dans l'arborescence vous donnera O(log n)au lieu de O(n)(où n= nombre de segments de ligne pour la courbe)


Cette solution est logique pour moi et est certainement la plus facile à comprendre et je pourrais me contenter d'elle. Mais je suis curieux de savoir s'il existe une option plus "pure".
paldepind

5

L'intersection entre une ligne et une courbe de Bézier est obtenue mathématiquement en subdivisant la courbe. Cela signifie s'appuyer sur la propriété de coque convexe de la courbe et la diviser en arcs plus petits avec différents polygones de contrôle de façon divisée et impera.

Cet article le couvre jusqu'à un certain point: http://students.cs.byu.edu/~tom/557/text/cic.pdf .

La bonne partie est que l'algorithme fonctionne avec n'importe quelle ligne, il vous suffit d'appliquer une transformation rigide à la courbe afin que vous puissiez considérer votre ligne cible comme parallèle à l'axe Ox.

De même, vous pouvez comparer le cercle et le polygone de chacun de ces arcs de Bézier lorsque vous subdivisez un arc de Bézier en deux sous-arcs. Le cercle doit intersecter le polygone de contrôle d'un arc pour qu'un test de courbe à cercle ait un sens.


Je n'ai pas encore lu l'article. Mais comment passer d'une intersection entre une ligne et une courbe de Bézier à une intersection entre un cercle et une Bézier? Vérifier la collision contre un cercle et un polygone me semble un peu trop compliqué.
paldepind
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.