Einheit - Wie man ein Schiff in einem 2D-Top-Down-Spiel realistisch zu einem Punkt bewegt

14

Ich versuche, ein Segelschiff an den Punkt zu bewegen, an dem ich mit der Maus geklickt habe. Diese Bewegung sollte realistisch sein (Ruder auf der Rückseite, auf der sich das Schiff bewegt). Wenn Sie also mit der linken Maustaste klicken und sich vor dem Schiff befinden, sollte sich das Schiff anschließend mit einem kurvigen Pfad dorthin bewegen, um die richtige Drehung zu erzielen

ich würde mich freuen wenn mir jemand bei diesem problem helfen könnte danke Schiffsbewegung

DavidT
quelle
1
Wie Ihr Bild Segel abzubilden scheint: Sollte Wind berücksichtigt werden? Einige Manöver sind unmöglich, mit dem falschen Wind oder einem Mangel davon zu tun.
Niemand
Mehr zu dem Punkt, realistisch aussehendes Segelschiff Bewegung wirklich erfordert Wind zu berücksichtigen sind ; es zu ignorieren wäre fast so, als würde man die Schwerkraft beim Springen ignorieren. Sie brauchen nicht unbedingt ein besonders detailliertes Windmodell, aber Sie müssen berücksichtigen, dass Ihre Schiffe vom Wind in ihren Segeln (und dem Wasser gegen Kiel und Ruder) herumgeschoben werden. Insbesondere können Schiffe nicht direkt gegen den Wind segeln. sie müssen schlagen ihren Weg dort statt.
Ilmari Karonen
Üblicherweise kann ein "goto point" in eine Rotationsphase und eine Vorwärtsbewegungsphase aufgeteilt werden. Nehmen Sie den gleichen Ansatz, aber erzwingen Sie für die Drehung eine Vorwärtsbewegung. Beispiel: Jedes x Rad der Drehung bewegt das Boot um y Meter vorwärts
dnk drone.vs.drones

Antworten:

7

Siehe diese Seite

Hinzufügen realistischer Kurven

Der nächste Schritt ist das Hinzufügen realistischer Kurven für unsere Einheiten, damit sie nicht jedes Mal, wenn sie sich drehen müssen, abrupt ihre Richtung ändern. Eine einfache Lösung besteht darin, die abrupten Ecken mit einem Spline in Kurven zu glätten. Dies löst zwar einige der ästhetischen Probleme, führt jedoch bei den meisten Einheiten zu physisch sehr unrealistischen Bewegungen. Beispielsweise könnte eine abrupte Kurvenfahrt eines Panzers in eine enge Kurve umgewandelt werden, aber die Kurve wäre immer noch viel enger, als der Panzer tatsächlich ausführen könnte.

Für eine bessere Lösung müssen wir zunächst den Wenderadius unserer Einheit kennen. Der Wenderadius ist ein ziemlich einfaches Konzept: Wenn Sie sich auf einem großen Parkplatz in Ihrem Auto befinden und das Rad so weit wie möglich nach links drehen, um in einem Kreis zu fahren, ist der Radius dieses Kreises Ihr Wenderadius Radius. Der Wenderadius eines Volkswagen Käfers ist wesentlich kleiner als der eines großen SUV, und der Wenderadius einer Person ist wesentlich kleiner als der eines großen, schwerfälligen Bären.

Nehmen wir an, Sie befinden sich an einem bestimmten Punkt (Ursprung) und weisen in eine bestimmte Richtung, und Sie müssen zu einem anderen Punkt (Ziel) gelangen, wie in Abbildung 5 dargestellt. Der kürzeste Weg wird gefunden, indem Sie nach links bis zu Ihnen abbiegen Gehen Sie im Kreis, bis Sie direkt auf das Ziel gerichtet sind, und gehen Sie dann vorwärts oder indem Sie nach rechts abbiegen und das Gleiche tun. Abbildung 5: Ermitteln des kürzesten Pfades vom Ursprung zum Ziel.

In Abbildung 5 ist der kürzeste Weg eindeutig die grüne Linie unten. Dieser Pfad ist aufgrund einiger geometrischer Beziehungen recht einfach zu berechnen (siehe Abbildung 6).

Abbildung 6: Berechnung der Pfadlänge

Zuerst berechnen wir den Ort des Punktes P, der der Mittelpunkt unseres Wendekreises ist und immer einen Radius r vom Startpunkt entfernt ist. Wenn wir von unserer anfänglichen Richtung nach rechts abbiegen, bedeutet dies, dass P in einem Winkel von (initial_direction - 90) vom Ursprung steht.

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

Nachdem wir die Position des Mittelpunkts P kennen, können wir die Entfernung von P zum Ziel berechnen, die im Diagramm als h angezeigt wird:

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

An dieser Stelle möchten wir auch überprüfen, ob das Ziel nicht innerhalb des Kreises liegt, da wir es sonst niemals erreichen könnten:

if (h < r)
    return false

Jetzt können wir die Länge des Segments d berechnen, da wir bereits die Längen der beiden anderen Seiten des rechten Dreiecks kennen, nämlich h und r. Wir können den Winkel auch aus der Dreiecksbeziehung bestimmen:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

Um schließlich den Punkt Q zu bestimmen, an dem der Kreis verlassen und auf der Geraden begonnen werden soll, müssen wir den Gesamtwinkel + kennen, der leicht als Winkel von P zum Ziel bestimmt werden kann:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

Die obigen Berechnungen stellen den Rechtskurvenpfad dar. Der Pfad auf der linken Seite kann genauso berechnet werden, außer dass wir zur Berechnung von angleToP 90 zu initial_direction addieren und später - anstelle von + verwenden. Nachdem wir beide berechnet haben, sehen wir einfach, welcher Pfad kürzer ist und verwenden diesen.

Bei der Implementierung dieses und der folgenden Algorithmen verwenden wir eine Datenstruktur, in der bis zu vier verschiedene "Liniensegmente" gespeichert sind, von denen jedes entweder gerade oder gekrümmt ist. Für die hier beschriebenen Kurvenpfade werden nur zwei Segmente verwendet: ein Bogen, gefolgt von einer geraden Linie. Die Datenstruktur enthält Elemente, die angeben, ob das Segment ein Bogen oder eine gerade Linie ist, die Länge des Segments und seine Startposition. Wenn das Segment eine gerade Linie ist, gibt die Datenstruktur auch den Winkel an. Bei Bögen werden der Mittelpunkt des Kreises, der Startwinkel auf dem Kreis und die vom Bogen abgedeckten Bogenmaßzahlen angegeben.

Nachdem wir den für die Verbindung zwischen zwei Punkten erforderlichen gekrümmten Pfad berechnet haben, können wir unsere Position und Richtung zu jedem beliebigen Zeitpunkt leicht berechnen, wie in Listing 2 gezeigt.

Listing 2. Berechnung der Position und Orientierung zu einem bestimmten Zeitpunkt.

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length
Draco18s vertraut SE nicht mehr
quelle
4
Diese Antwort befasst sich nicht wirklich mit der Physik von Schiffen. Ich finde es auch problematisch, dass es sich im Grunde genommen um einen Link zu und einen längeren Auszug von einer anderen Website handelt (ich bin nicht sicher, ob dies legal ist).
Niemand
Als ich das letzte Mal eine vorhandene Ressource bereitgestellt habe, die eine Lösung für die gestellte Frage darstellt, wurde ich gebeten, den Inhalt des Links anzugeben, falls die Zielsite nicht mehr vorhanden ist. Jetzt werde ich gebeten, den Inhalt nicht einzuschließen. Entscheide dich.
Draco18s vertraut SE
3
@Draco18s: Sie sollten die wesentlichen Punkte des verlinkten Materials in Ihren eigenen Worten zusammenfassen. (Oder, noch besser, beantworten Sie die Frage auf der Grundlage Ihrer eigenen Erfahrung und verwenden Sie nur Links als Hintergrundmaterial oder zum weiteren Lesen.) Kurze Zitate sind im Allgemeinen in Ordnung, insbesondere in Situationen, in denen sie nicht wirklich vermieden werden können (z. B. Zitieren von jemandem genauem) Worte, die zeigen, dass sie wirklich etwas gesagt haben), aber einen wesentlichen Teil eines Artikels zu zitieren, geht wirklich über den fairen Gebrauch hinaus .
Ilmari Karonen
Wenn sich der Punkt innerhalb des Kreises befindet, können Sie ein wenig hinausgehen und zurückkommen.
user253751
(Ps. Siehe auch diese beiden Fragen zu meta.SE.)
Ilmari Karonen
7

Als einfache Lösung können Sie, wie bereits in einem Kommentar erwähnt, diesen Ansatz ausprobieren:

Betrachten Sie eine Phase, in der Sie das Schiff in die Zielrichtung richten. In dieser Phase wenden Sie eine Drehung auf den Schluck, aber auch eine Vorwärtsbewegung an. Wenn das Schiff bereits dem Ziel zugewandt ist, können Sie eine volle Vorwärtsgeschwindigkeit anwenden. Ich habe einen Test in love2d arrangiert, hier folgen Sie der Schiffsaktualisierung.

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

Bildbeschreibung hier eingeben

Die Beispiel - Animation zeigt (die letzte Schleife) ein Fall , in dem das Schiff nicht das Ziel erreichen kann, da die Kombination von Dreh- und Vorwärtsgeschwindigkeit definiert ein Wenderadius zu groß, in diesen Fällen kann das „Biene nützlich reduziert turnForwordSpeedes“ oder besser machen abhängig von winkelabstand ( a) und zielabstand.

dnk drone.vs.drones
quelle
Dies ist eine nette Antwort, aber sie kann für das OP realistisch genug sein oder auch nicht. Im Gegensatz zu beispielsweise Autos haben Schiffe keinen wirklichen "Wenderadius": Die meisten Schiffe mit Eigenantrieb (Motor / Mensch) können im Wesentlichen einen Cent drehen, während Segelschiffe vom Wind abhängen und tatsächlich eine negative effektive Wendung haben können Radius beim Wenden in dem Sinne, dass das Schiff nach rechts driften kann, wenn es nach links in den Wind dreht. Was Schiffe haben, ist Trägheit (und Widerstand): Sie können sich nicht sofort drehen oder bewegen, und sobald sie sich bewegen oder drehen, brauchen sie etwas Zeit und Kraft, um anzuhalten. Habe trotzdem eine +1.
Ilmari Karonen
Ich danke Ihnen sehr für Ihre Antwort!!! :) Sie, mein Herr, sind mein Held!
DavidT
@DavidT Markieren Sie dann seine / ihre Antwort als die akzeptierte, wenn Ihr Problem damit zufriedenstellend gelöst werden konnte. :)
MAnd
-2

Unity Nav-Mesh-System, es würde wahrscheinlich tun, was Sie wollen, mit ein wenig herumspielen mit den Nav-Agent-Werten.

Nav Meshes sind ziemlich einfach zu bedienen. Und nur im Top-Down-Setup verwendbar (oder zumindest nur für x / z-Bewegungen verfügbar)

Unity-Handbuchseite zum Einrichten eines Navigationsnetzes

Grundsätzlich können Sie ein beliebiges Formnetz verwenden, um einen Navigationsbereich zu backen und Ihren Objekten Navigationsagenten hinzuzufügen, damit diese ihre Pfade um ein Navigationsnetz finden

ProtoJazz
quelle
Ich finde Draco18s Antwort auch in dieser Hinsicht mangelhaft. Ihre Antwort ist jedoch keine echte Antwort und eher ein Kommentar.
Niemand
2
Dies ist ein guter Vorschlag, aber um eine gute Antwort zu finden, sind Unterstützung und Informationen zur Implementierung erforderlich. Fügen Sie einige Informationen zum Konfigurieren von Navigationsnetzen hinzu, damit dies eine gute Antwort ist. Ich denke, das ist, was die obigen Kommentatoren zu sagen versuchen :)
sirdank