Comment trouver des cellules de grille 2D balayées par un cercle en mouvement?

9

Je fais un jeu basé sur une grille 2D, avec certaines cellules passables et d'autres non. Les objets dynamiques peuvent se déplacer en continu, indépendamment de la grille, mais doivent entrer en collision avec des cellules infranchissables.

J'ai écrit un algorithme pour tracer un rayon sur la grille, qui me donne toutes les cellules que le rayon intersecte. Cependant, les objets réels ne sont pas de taille ponctuelle; Je les représente actuellement sous forme de cercles. Mais je ne peux pas trouver d'algorithme efficace pour tracer un cercle en mouvement. Voici une photo de ce dont j'ai besoin: entrez la description de l'image ici

Les nombres indiquent dans quel ordre le cercle entre en collision avec les cellules de la grille. Quelqu'un connaît-il l'algorithme pour trouver ces collisions? De préférence en C #.

Mettre à jour Le cercle peut être plus grand qu'une seule cellule de grille.

Ça ne fait rien
la source
mmh pourquoi 3 entrent en collision AVANT 4?
FxIII
@FxIII J'ai en fait déplacé le cercle dans l'image, et il a frappé 3 avant 4. Seulement à peine, mais toujours avant.
Nevermind

Réponses:

6

Je pense que votre dessin est un peu trompeur car vous choisissez de dessiner des traits à partir du point du cercle tangent à votre direction de déplacement. Je peux voir que les collisions avec les bords de votre grille se produisent lorsque les points HAUT et GAUCHE de votre cercle touchent un bord.

Soit C votre centre et r le rayon donc P ' = C + ( r , 0) et P " = C + (0, r).

Si D est votre vecteur de direction (le verseur), vous avez deux lignes:

R '= D · t + P' ,

R "= D · t + P"

Vous devez simplement trouver l'intersection de ces lignes avec les lignes d'équation:

y = i et y = i qui sont les bords de votre grille!

La solution est simple car il suffit de considérer la composante x ou y de R 'et R ". Vous trouverez la valeur t s pour chaque insertion, et les points pour ces t s, il vous suffit de trier ces points par t et vous sont fait.

Je crois que vous pouvez facilement dire quelle cellule est touchée si vous connaissez le point d'intersection.

Cela fonctionne si r <1 (la largeur et la hauteur des cellules).

Cela fonctionne également pour les autres cas en faisant simplement une réflexion sur P ' et P " . Nous choisissons TOP et LEFT en raison de la direction, BOTTOM et RIGHT doivent être pris en compte pour la direction opposée, vous comprenez pourquoi.

Regardez maintenant cette image: grand cercle

Le cercle est plus grand qu'une seule cellule et nous supposons qu'il va dans la même direction que votre dessin. P1 est le premier point qui va toucher, P2 est le second, P3 est inutile car se trouve dans la moitié inférieure. Ce que vous devez faire est de projeter des rayons de P1 et P2 comme nous l'avons vu précédemment et de faire de même pour les lignes verticales.

En général, vous aurez d'autres points de départ avec le TOP et le GAUCHE d'où tirer vos rayons, plus votre cercle est grand, plus il y a de rayons à lancer.

Pour être honnête, vous pouvez éviter de tirer sur tous ces rayons en tenant compte de la géométrie, mais cela peut rendre les choses plus difficiles à comprendre.

FxIII
la source
Oui, j'ai pensé moi-même aux points P 'et P ", mais je n'ai pas pu déterminer quoi faire lorsque le cercle est plus grand qu'une seule cellule. Des points supplémentaires ont vraiment du sens (et je n'ai évidemment besoin que d'ajouter des rayons entre P' et P ")
Nevermind
Des considérations géométriques peuvent être faites pour simplifier les calculs, mais l'utilisation de l'implémentation peut vous conduire aux mêmes résultats par expérience.
FxIII
Est-il clair que vous devez tester séparément les lignes de quadrillage horizontales et verticales?
FxIII
Je pense que vous devez également vérifier quand le cercle couvre un sommet de la grille, car le cercle entrera en collision avec la cellule adjacente en diagonale à son coin, mais ce ne sera pas nécessairement le point haut / gauche / bas / le plus à droite du cercle qui le touchera en premier. (et vous détecterez la collision trop tôt.) Exemple: carrés 3,4,5 dans l'exemple de diagramme de la question. Ils sont frappés dans l'ordre (3 puis 4 puis 5) mais votre algorithme détecterait 4 et 5 simultanément.
finnw
@finnw ils ne touchent simultanément que si le cicle se déplace exactement dans la direction de la bissectrice.
FxIII
1

Si vous souhaitez utiliser votre algorithme de collision de rayons, vous pouvez choisir huit points sur chaque cercle (par incréments de 45 degrés, alignés avec votre grille carrée), et utiliser la collision de rayons entre les points correspondants (c'est-à-dire du haut d'un cercle en haut de l'autre). L'union de toutes ces collisions de rayons est l'ensemble des cellules intersectées.

Vous pourriez probablement améliorer un peu cela - par exemple en utilisant le segment de ligne du centre d'un cercle au centre de l'autre, mais prolongé de chaque côté par le rayon du cercle, ainsi que les segments de ligne parallèles sur de chaque côté aux extrémités des cercles.

TreDubZedd
la source
8 rayons garantiront probablement toutes les intersections, mais ils ne les donneront pas dans le bon ordre. Et pour les collisions, j'ai besoin d'ordre, pas seulement d'une liste de cellules.
Nevermind
Augmentez votre algorithme de collision de rayons pour conserver une valeur t pour chaque collision. Lorsque vous obtenez l'union des cellules, vous pouvez trier la valeur t pour obtenir l'ordre correct.
TreDubZedd
Mais comment comparer la valeur t de différents rayons?
Nevermind
Si vous êtes toujours originaire du même cercle, vos points d'intersection seront à des distances de ce cercle. Lorsque vous arrivez dans une cellule que vous avez déjà vue, si la valeur t de la collision actuelle est plus petite que la précédente, utilisez-la ... sinon, jetez l'intersection (en conservant l'original).
TreDubZedd
1
Vous pourrez peut-être vous en sortir avec seulement deux rayons sur les côtés du cercle perpendiculaires au mouvement, puis vous pouvez voir quelles tuiles sont touchées par les rayons et vous pouvez vérifier le reste pour voir si leurs centres se situent entre les deux rayons. La seule chose qui devrait manquer serait que les choses entrent en collision au début ou à la fin du cercle, mais ce ne sont que deux cercles et peuvent être manipulées facilement. Il peut être un peu plus lent que huit rayons, je n'en suis pas certain; mais vous n'auriez pas besoin de mettre le nombre à l'échelle en fonction de la taille du cercle.
Lunin
1

Je ne dis pas que c'est une analogie parfaite, mais vous pourriez penser à l' algorithme de ligne de Bresenham . Une modification de cet algorithme ou de l'une de ses extensions pourrait être utile, surtout si vous l'associez à certains des autres articles et commentaires. En règle générale, cet algorithme ne concerne pas la commande, mais je pense que vous seriez en mesure d'ajouter cela de manière assez triviale.

Ryan
la source
J'y pensais aussi, mais à mon avis, ce n'est pas le bon algorithme. Bresenham choisit un seul pixel, il a besoin de tout. Et il serait difficile d'adapter bresenham au cercle insted d'un seul pixel.
zacharmarz
Le ray tracer que j'utilise est en fait un peu basé sur l'algorithme de Bresenham. J'ai du mal à le généraliser d'une ligne fine à une ligne "grasse", en particulier à balayage circulaire.
Nevermind