Ich habe in letzter Zeit ein wenig Seilphysik ausprobiert und festgestellt, dass die "Standard" -Lösung, ein Seil aus einer Reihe von Gegenständen herzustellen, die mit Federn oder Gelenken aneinandergereiht sind, unbefriedigend ist. Besonders wenn Seilschwingen für das Gameplay relevant ist. Die Fähigkeit eines Seils, sich einzuwickeln oder durchzubiegen, interessiert mich nicht wirklich (dies kann ohnehin für visuelle Zwecke vorgetäuscht werden).
Für das Gameplay ist es wichtig, dass sich das Seil um die Umgebung wickelt und anschließend abwickelt. Es muss sich nicht einmal wie ein Seil verhalten - ein "Draht" aus geraden Liniensegmenten würde ausreichen. Hier ist eine Illustration:
Dies ist dem "Ninja Rope" aus dem Spiel Worms sehr ähnlich.
Da ich eine 2D-Physik-Engine verwende, besteht meine Umgebung aus konvexen 2D-Polygonen. (Insbesondere benutze ich SAT in Farseer.)
Meine Frage lautet also: Wie würden Sie den "Wrapping" -Effekt implementieren?
Es scheint ziemlich offensichtlich, dass der Draht aus einer Reihe von Liniensegmenten bestehen wird, die sich "teilen" und "verbinden". Das letzte (aktive) Segment dieser Linie, an dem das sich bewegende Objekt anhaftet, ist eine Verbindung mit fester Länge.
Aber was ist die Mathematik / der Algorithmus, um zu bestimmen, wann und wo das aktive Liniensegment aufgeteilt werden muss? Und wann muss es mit dem vorherigen Segment verbunden werden?
(Zuvor wurde diese Frage auch dazu gestellt, dies für eine dynamische Umgebung zu tun. Ich habe beschlossen, dies in andere Fragen aufzuteilen.)
quelle
Es ist eine Weile her, dass ich Worms gespielt habe, aber soweit ich mich erinnere, gibt es immer nur einen (geraden) Seilabschnitt, der sich gleichzeitig bewegt, wenn sich das Seil um Dinge wickelt. Der Rest des Seils wird statisch
Es ist also sehr wenig Physik beteiligt. Der aktive Abschnitt kann als einzelne steife Feder mit einer Masse am Ende modelliert werden
Das interessante Bit wird die Logik zum Teilen / Verbinden inaktiver Abschnitte des Seils mit / von dem aktiven Abschnitt sein.
Ich würde mir vorstellen, dass es zwei Hauptoperationen geben würde:
'Split' - Das Seil hat etwas gekreuzt. Teilen Sie es an der Kreuzung in einen inaktiven Abschnitt und den neuen, kürzeren, aktiven Abschnitt auf
'Verbinden' - Das aktive Seil hat eine Position erreicht, an der der nächste Schnittpunkt nicht mehr vorhanden ist (dies kann nur ein einfacher Winkel- / Punkt-Produkttest sein?). Verbinden Sie 2 Abschnitte erneut und erstellen Sie einen neuen, längeren, aktiven Abschnitt
In einer aus 2D-Polygonen aufgebauten Szene sollten sich alle Teilungspunkte an einem Scheitelpunkt auf dem Kollisionsnetz befinden. Die Kollisionserkennung kann sich vereinfachen, wenn das Seil bei dieser Aktualisierung einen Scheitelpunkt überquert, das Seil an diesem Scheitelpunkt teilen / verbinden.
quelle
Sehen Sie sich an, wie das Ninja-Seil in Gusanos implementiert wurde:
Relevanter Auszug aus ninjarope.cpp :
quelle
Ich fürchte, ich kann Ihnen keinen konkreten Algorithmus auf den Kopf stellen, aber mir fällt auf, dass es nur zwei Dinge gibt, die für die Erkennung einer Kollision mit dem Ninja-Seil von Bedeutung sind: alle potenziell kollidierenden Scheitelpunkte auf Hindernissen innerhalb eines Radius von der letzten "Teilung" gleich der verbleibenden Länge des Segments; und die aktuelle Schwenkrichtung (im oder gegen den Uhrzeigersinn). Wenn Sie eine temporäre Liste von Winkeln vom "geteilten" Scheitelpunkt zu jedem der nahe gelegenen Scheitelpunkte erstellt haben, muss sich Ihr Algorithmus nur darum kümmern, ob Ihr Segment für einen bestimmten Scheitelpunkt über diesen Winkel hinausschwingen würde. Wenn dies der Fall ist, müssen Sie eine geteilte Operation ausführen, die kinderleicht ist. Es ist nur eine Linie vom letzten geteilten Scheitelpunkt zum neuen geteilten Punkt, und dann wird ein neuer Rest berechnet.
Ich denke nur die Eckpunkte sind wichtig. Wenn Sie Gefahr laufen, auf einem Hindernis ein Segment zwischen den Eckpunkten zu treffen, sollte Ihre normale Kollisionserkennung für den am Ende des Seils hängenden Kerl aktiviert werden. Mit anderen Worten, Ihr Seil wird immer nur "hängen bleiben" Ecken sowieso, so dass die Segmente dazwischen keine Rolle spielen.
Tut mir leid, dass ich nichts Konkretes habe, aber hoffentlich bringt dich das dahin, wo du konzeptionell sein musst, um dies zu verwirklichen. :)
quelle
Hier ist ein Beitrag mit Links zu Artikeln über ähnliche Arten von Simulationen (eher im technischen / akademischen Kontext als für Spiele): https://gamedev.stackexchange.com/a/10350/6398
Ich habe mindestens zwei verschiedene Ansätze zur Kollisionserkennung + Reaktion für diese Art von "Draht" -Simulation ausprobiert (wie im Spiel Umihara Kawase zu sehen); Zumindest denke ich, das ist es, wonach Sie suchen - es scheint keinen bestimmten Begriff für diese Art von Simulation zu geben, ich neige dazu, es eher als "Draht" als als "Seil" zu bezeichnen, weil es den meisten Menschen so vorkommt Betrachten Sie "Seil" als Synonym für "eine Kette von Partikeln". Und wenn Sie das klebrige Verhalten eines Ninja-Seils wollen (dh es kann drücken UND ziehen), ähnelt dies eher einem starren Draht als einem Seil. Sowieso..
Die Antwort von Pekuja ist gut. Sie können eine kontinuierliche Kollisionserkennung implementieren, indem Sie die Zeit berechnen, in der der vorzeichenbehaftete Bereich der drei Punkte 0 ist.
(Ich kann mich nicht vollständig an OTOH erinnern, aber Sie können es wie folgt angehen: Ermitteln Sie die Zeit t, wenn der Punkt a in der durch b, c verlaufenden Linie enthalten ist 0, um Werte von t) zu finden, und dann, wenn eine gültige Zeit 0 <= t <1 gegeben ist, finde die parametrische Position s von a auf dem Segment bc, dh a = (1-s) b + s c und wenn a zwischen liegt b und c (dh wenn 0 <= s <= 1) ist es eine gültige Kollision.
AFAICR Sie können auch umgekehrt vorgehen (dh nach s auflösen und dieses dann einstecken, um t zu finden), aber es ist viel weniger intuitiv. (Es tut mir leid, wenn dies keinen Sinn ergibt, ich habe keine Zeit, meine Notizen auszugraben, und es sind ein paar Jahre vergangen!)
So können Sie jetzt alle Zeiten berechnen, zu denen Ereignisse auftreten (dh Seilknoten sollten eingefügt oder entfernt werden). Verarbeiten Sie das früheste Ereignis (Einfügen oder Entfernen eines Knotens) und wiederholen / rekursieren Sie es, bis zwischen t = 0 und t = 1 keine Ereignisse mehr vorhanden sind.
Eine Warnung zu diesem Ansatz: Wenn die Objekte, um die sich das Seil wickeln kann, dynamisch sind (insbesondere, wenn Sie sie und ihre Auswirkungen auf das Seil simulieren und umgekehrt), kann es zu Problemen kommen, wenn diese Objekte jeweils durchtrennen Anderes - der Draht kann sich verwickeln. Und es wird definitiv eine Herausforderung sein, diese Art von Interaktion / Bewegung (die Ecken von Objekten rutschen durcheinander) in einer Box2D-ähnlichen Physiksimulation zu verhindern. Geringe Durchdringungswerte zwischen Objekten sind in diesem Kontext normal.
(Zumindest .. das war ein Problem mit einer meiner Implementierungen von "wire".)
Eine andere Lösung, die viel stabiler ist, aber unter bestimmten Bedingungen einige Kollisionen auslässt, besteht darin, nur statische Tests zu verwenden (dh sich keine Gedanken über die zeitliche Reihenfolge zu machen, sondern jedes Segment rekursiv in Kollisionen zu unterteilen, wie Sie es finden) viel robuster - der Draht verwickelt sich nicht in Ecken und kleine Mengen an Eindringen sind in Ordnung.
Ich denke, Pekujas Ansatz funktioniert auch hier, es gibt jedoch alternative Ansätze. Ein Ansatz, den ich verwendet habe, besteht darin, zusätzliche Kollisionsdaten hinzuzufügen: Fügen Sie an jedem konvexen Scheitelpunkt v der Welt (dh an den Ecken von Formen, um die sich das Seil wickeln kann) einen Punkt u hinzu, der das gerichtete Liniensegment uv bildet, wobei u einiges ist Punkt "innerhalb der Ecke" (dh innerhalb der Welt, "hinter" v; um u zu berechnen, können Sie einen Strahl von v aus entlang seiner interpolierten Normalen nach innen werfen und eine Strecke nach v anhalten oder bevor der Strahl einen Rand der Welt schneidet und Sie können die Segmente auch manuell mit einem visuellen Werkzeug / Ebenen-Editor in die Welt malen.
Wie auch immer, Sie haben jetzt eine Reihe von "Ecklinien" UV; Überprüfen Sie für jedes UV und jedes Segment ab in der Leitung, ob sich ab und uv überschneiden (dh statische, boolesche Lineseg-Lineseg-Schnittabfrage). Wenn ja, rekursieren Sie (teilen Sie das Lineseg ab in av und vb, dh fügen Sie v ein) und notieren Sie, in welche Richtung das Seil bei v gebogen ist. Prüfen Sie dann für jedes Paar benachbarter Linesegs ab, bc im Draht, ob die aktuelle Biegerichtung bei b vorliegt ist dasselbe wie bei der Erzeugung von b (alle diese "Biegerichtungstests" sind nur Tests mit vorzeichenbehafteten Bereichen); Wenn nicht, füge die beiden Segmente zu ac zusammen (dh entferne b).
Oder vielleicht habe ich fusioniert und dann geteilt, vergesse ich - aber es funktioniert definitiv in mindestens einer der beiden möglichen Bestellungen! :)
Wenn Sie alle für den aktuellen Frame berechneten Drahtsegmente vorausgesetzt haben, können Sie eine Abstandsbeschränkung zwischen den beiden Drahtendpunkten simulieren (und Sie können sogar die inneren Punkte einbeziehen, dh die Kontaktpunkte zwischen Draht und Welt, aber das ist etwas komplizierter ).
Wie auch immer, hoffentlich wird dies von Nutzen sein ... die Artikel in dem Beitrag, den ich auch verlinkt habe, sollten Ihnen auch einige Ideen geben.
quelle
Ein Ansatz besteht darin, das Seil als kollidierbare Partikel zu modellieren, die durch Federn verbunden sind. (ziemlich steif, möglicherweise sogar nur als Knochen). Die Partikel kollidieren mit der Umgebung und sorgen dafür, dass sich das Seil um Gegenstände wickelt.
Hier ist eine Demo mit Quelle: http://www.ewjordan.com/rgbDemo/
(Gehen Sie in der ersten Ebene nach rechts, es gibt ein rotes Seil, mit dem Sie interagieren können.)
quelle