Ich mache ein Spiel basierend auf einem 2D-Gitter, wobei einige Zellen passierbar sind und andere nicht. Dynamische Objekte können sich unabhängig vom Gitter kontinuierlich bewegen, müssen jedoch mit unpassierbaren Zellen kollidieren.
Ich habe einen Algorithmus geschrieben, um einen Strahl gegen das Gitter zu verfolgen, der mir alle Zellen gibt, die der Strahl schneidet. Das tatsächliche Objekt hat jedoch keine Punktgröße. Ich vertrete sie derzeit als Kreise. Aber ich kann keinen effektiven Algorithmus finden, um einen sich bewegenden Kreis zu verfolgen. Hier ist ein Bild von dem, was ich brauche:
Die Zahlen zeigen, in welcher Reihenfolge der Kreis mit Gitterzellen kollidiert. Kennt jemand den Algorithmus, um diese Kollisionen zu finden? Vorzugsweise in C #.
Aktualisieren Der Kreis kann größer als eine einzelne Gitterzelle sein.
quelle
Antworten:
Ich denke, Ihre Zeichnung ist etwas irreführend, weil Sie Striche vom Punkt auf dem Kreis zeichnen, der Ihre Bewegungsrichtung tangiert. Ich kann sehen, dass die Kollisionen mit Ihren Gitterkanten auftreten, wenn die oberen und linken Punkte Ihres Kreises eine Kante berühren.
Sei C dein Zentrum und r der Radius, also P ' = C + ( r , 0) und P " = C + (0, r).
Wenn D Ihr Richtungsvektor (der Versor) ist, haben Sie zwei Linien:
R '= D · t + P' ,
R = D · t + P
Sie müssen einfach den Schnittpunkt dieser Linien mit den Gleichungslinien finden:
y = i und y = i , das sind die Kanten Ihres Gitters!
Die Lösung ist einfach, da Sie einfach die x- oder y-Komponente von R 'und R "berücksichtigen müssen. Sie finden den t s -Wert für jeden Einschnitt und die Punkte für diese t s. Sortieren Sie diese Punkte einfach nach t und Ihnen sind fertig.
Ich glaube, Sie können leicht sagen, welche Zelle getroffen wird, wenn Sie den Schnittpunkt kennen.
Dies funktioniert, wenn r <1 (die Zellenbreite und -höhe) ist.
Es funktioniert auch für die anderen Fälle, in denen einfach P ' und P " berücksichtigt werden . Wir wählen TOP und LEFT aufgrund der Richtung. BOTTOM und RIGHT sollten für die entgegengesetzte Richtung berücksichtigt werden. Sie verstehen, warum.
Schauen Sie sich nun dieses Bild an:
Der Kreis ist größer als eine einzelne Zelle und wir nehmen an, dass er in die gleiche Richtung wie Ihre Zeichnung verläuft. P1 ist der erste Punkt, der sich berührt, P2 ist der zweite, P3 ist nutzlos, weil er sich in der unteren Hälfte befindet. Was Sie tun müssen, ist, Strahlen von P1 und P2 wie zuvor gesehen zu werfen und dasselbe für die vertikalen Linien zu tun.
Im Allgemeinen haben Sie neben den oberen und linken Punkten andere Ausgangspunkte, von denen aus Sie Ihre Strahlen abschießen. Je größer Ihr Kreis ist, desto mehr Strahlen müssen geworfen werden.
Um ehrlich zu sein, können Sie es vermeiden, all diese Strahlen unter geometrischen Gesichtspunkten abzuschießen, aber das kann das Verständnis der Dinge erschweren.
quelle
Wenn Sie Ihren Strahlenkollisionsalgorithmus verwenden möchten, können Sie acht Punkte auf jedem Kreis auswählen (in Schritten von 45 Grad, ausgerichtet an Ihrem quadratischen Gitter) und die Strahlenkollision zwischen entsprechenden Punkten verwenden (dh von oben auf einem Kreis nach oben). Die Vereinigung all dieser Strahlenkollisionen ist die gesamte Menge der durchschnittenen Zellen.
Sie könnten dies wahrscheinlich ein wenig verbessern - zum Beispiel, indem Sie das Liniensegment vom Mittelpunkt eines Kreises zum Mittelpunkt des anderen Kreises verwenden, das jedoch auf beiden Seiten um den Radius des Kreises sowie die parallelen Liniensegmente erweitert wird zu beiden Seiten an den Enden der Kreise.
quelle
Ich sage nicht, dass dies eine perfekte Analogie ist, aber Sie könnten über Bresenhams Linienalgorithmus nachdenken . Eine Änderung dieses Algorithmus oder einer seiner Erweiterungen kann hilfreich sein, insbesondere wenn Sie ihn mit einigen anderen Posts und Kommentaren koppeln. Normalerweise befasst sich dieser Algorithmus nicht mit der Bestellung, aber ich würde denken, dass Sie dies ziemlich trivial hinzufügen können.
quelle