Jedność - jak realistycznie przenieść statek do punktu w odgórnej grze 2D

14

Próbuję przenieść żaglowiec do miejsca, w którym kliknąłem myszką. ruch ten powinien być realistyczny (wiosło z tyłu, w którym porusza się statek), więc jeśli lewy przycisk myszy zostanie kliknięty, a przed statkiem statek powinien następnie przejść tam zakrzywioną ścieżką, aby uzyskać właściwy obrót

Byłbym zadowolony, gdyby ktoś mógł mi pomóc z tym problemem, dziękuję ruch statków

DavidT
źródło
1
Ponieważ twoje zdjęcie wydaje się przedstawiać żagle: czy należy wziąć pod uwagę wiatr? Niektórych manewrów nie można wykonać przy złym wietrze lub jego braku.
Nikt
Co więcej, realistycznie wyglądający ruch żaglowców naprawdę wymaga uwzględnienia wiatru; ignorowanie tego byłoby prawie jak ignorowanie grawitacji podczas wykonywania skoków. Niekoniecznie potrzebujesz szczególnie szczegółowego modelu wiatru, ale musisz pamiętać, że twoje statki są popychane przez wiatr w żagle (i wodę na kilu i steru). W szczególności statki nie mogą pływać bezpośrednio pod wiatr; zamiast tego będą musieli się tam przebić .
Ilmari Karonen,
Zazwyczaj „punkt gotowości” można podzielić na fazę rotacji i fazę ruchu do przodu. Podejmij to samo podejście, ale nałóż na obrót ruch do przodu. Przykład każdego x rad rotacji przesuwa łódź do przodu o y metrów
dnk drone.vs.drones

Odpowiedzi:

7

Zobacz tę stronę

Dodawanie realistycznych zwrotów

Następnym krokiem jest dodanie realistycznych zakrętów dla naszych jednostek, aby nie wydawały się gwałtownie zmieniać kierunku za każdym razem, gdy muszą się obracać. Proste rozwiązanie polega na użyciu splajnu, aby wygładzić ostre rogi w zakręty. Chociaż rozwiązuje to niektóre problemy estetyczne, nadal powoduje fizycznie bardzo nierealistyczny ruch dla większości jednostek. Na przykład może zmienić nagłe zakręt zbiornika w ciasną zakręt, ale zakręt zakrętu byłby nadal znacznie ciaśniejszy, niż czołg mógłby faktycznie wykonać.

Aby uzyskać lepsze rozwiązanie, pierwszą rzeczą, którą musimy wiedzieć, jest promień skrętu naszego urządzenia. Promień skrętu jest dość prostą koncepcją: jeśli jesteś na dużym parkingu w samochodzie i obróć koło w lewo do oporu i kontynuuj jazdę po okręgu, promień tego koła to twój obrót promień. Promień skrętu Volkswagen Beetle będzie znacznie mniejszy niż w dużym SUV-ie, a promień skrętu osoby będzie znacznie mniejszy niż w przypadku dużego, ociężałego niedźwiedzia.

Powiedzmy, że jesteś w pewnym punkcie (początek) i skierowany w określonym kierunku, i musisz dotrzeć do innego punktu (miejsca docelowego), jak pokazano na rysunku 5. Najkrótszą ścieżkę można znaleźć, skręcając w lewo do samego końca może, idąc w kółko, dopóki nie zostaniesz bezpośrednio wskazany na miejsce docelowe, a następnie przejdź do przodu lub skręcając w prawo i robiąc to samo. Rysunek 5: Określanie najkrótszej ścieżki od początku do miejsca docelowego.

Na rycinie 5 najkrótsza trasa jest wyraźnie zieloną linią na dole. Ścieżka ta okazuje się dość prosta do obliczenia ze względu na pewne zależności geometryczne, zilustrowane na rycinie 6.

Rysunek 6: Obliczanie długości ścieżki.

Najpierw obliczamy położenie punktu P, który jest środkiem naszego koła zwrotnego i zawsze znajduje się w promieniu r od punktu początkowego. Jeśli skręcamy w prawo z naszego początkowego kierunku, oznacza to, że P znajduje się pod kątem (kierunek_ początkowy - 90) od początku, więc:

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

Teraz, gdy znamy położenie punktu środkowego P, możemy obliczyć odległość od P do miejsca docelowego, pokazaną jako h na schemacie:

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

W tym momencie chcemy również sprawdzić, czy cel nie znajduje się w kręgu, ponieważ gdyby tak było, nigdy byśmy go nie osiągnęli:

if (h < r)
    return false

Teraz możemy obliczyć długość odcinka d, ponieważ znamy już długości dwóch pozostałych boków prawego trójkąta, mianowicie h i r. Możemy również określić kąt na podstawie relacji prostokąt-trójkąt:

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

Na koniec, aby obliczyć punkt Q, w którym należy opuścić okrąg i zacząć od linii prostej, musimy znać całkowity kąt + i można go łatwo określić jako kąt od P do celu:

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)

Powyższe obliczenia przedstawiają ścieżkę skrętu w prawo. Ścieżkę po lewej stronie można obliczyć dokładnie w ten sam sposób, z tym wyjątkiem, że dodajemy 90 do initial_direction do obliczania angleToP, a później używamy - zamiast +. Po obliczeniu obu, po prostu widzimy, która ścieżka jest krótsza i używamy tej.

W naszej implementacji tego algorytmu i kolejnych, wykorzystujemy strukturę danych, która przechowuje do czterech różnych „segmentów linii”, z których każdy jest prosty lub zakrzywiony. Dla opisanych tutaj zakrzywionych ścieżek zastosowano tylko dwa segmenty: łuk, po którym następuje linia prosta. Struktura danych zawiera elementy, które określają, czy segment jest łukiem czy linią prostą, długość segmentu i jego pozycję początkową. Jeśli segment jest linią prostą, struktura danych określa również kąt; dla łuków określa środek okręgu, kąt początkowy na okręgu oraz całkowitą liczbę radianów pokrytych przez łuk.

Po obliczeniu zakrzywionej ścieżki niezbędnej do przejścia między dwoma punktami możemy łatwo obliczyć naszą pozycję i kierunek w dowolnym momencie, jak pokazano na Listingu 2.

WYKAZ 2. Obliczanie pozycji i orientacji w określonym czasie.

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 nie ufa już SE
źródło
4
Ta odpowiedź tak naprawdę nie dotyczy fizyki statków. Problematyczne jest również to, że jest to w zasadzie link do długiego fragmentu innej strony internetowej (nie jestem pewien co do legalności).
Nikt
Ostatnim razem, gdy podałem istniejący zasób, który był rozwiązaniem zadawanego pytania, zostałem poproszony o dołączenie treści łącza w przypadku, gdy witryna docelowa przestała istnieć. Teraz jestem proszony o nieuwzględnianie treści. Podejmij decyzję.
Draco18s nie ufa już SE
3
@ Draco18s: To, co powinieneś zrobić, to streścić najważniejsze punkty połączonego materiału własnymi słowami. (Lub, jeszcze lepiej, odpowiedz na pytanie na podstawie własnego doświadczenia i używaj tylko linków jako materiałów pomocniczych lub do dalszego czytania.) Krótkie cytaty są ogólnie OK, szczególnie w sytuacjach, w których nie można ich naprawdę uniknąć (np. Zacytowanie słowa, które pokazują, że naprawdę coś powiedzieli), ale zacytowanie znacznej części artykułu naprawdę wykracza poza dozwolony użytek .
Ilmari Karonen,
Jeśli punkt znajduje się w kręgu, możesz wyjść trochę i wrócić.
user253751,
(Ps. Zobacz także te dwa pytania dotyczące meta.SE.)
Ilmari Karonen,
7

Jako proste rozwiązanie, jak już powiedziałem w komentarzu, możesz wypróbować to podejście:

rozważ fazę, w której skierujesz statek w kierunku celu, w tej fazie zastosujesz obrót do łyka, ale także ruch do przodu. Gdy statek jest już ustawiony w kierunku celu, możesz zastosować pełną prędkość do przodu. Zorganizowałem test w love2d, tutaj zastosuj metodę aktualizacji statku.

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

wprowadź opis zdjęcia tutaj

Przykładowa animacja pokazuje (ostatnią pętlę) przypadek, w którym statek nie może osiągnąć celu, ponieważ połączenie prędkości zawracania i do przodu określa zbyt duży promień skrętu, w takim przypadku może być przydatne zmniejszenie „ turnForwordSpeed” lub lepiej zależy od odległości kątowej ( a) i odległości docelowej.

dnk drone.vs.drones
źródło
To ładna odpowiedź, ale może być lub nie być wystarczająco realistyczna dla PO. W przeciwieństwie do, powiedzmy, samochodów, statki nie mają tak naprawdę „promienia skrętu”: większość statków o napędzie własnym (silnik / człowiek) może zasadniczo włączyć dziesięciocentówkę, podczas gdy żaglówki zależą od wiatru i mogą faktycznie mieć ujemny efektywny obrót promień podczas halsowania, w tym sensie, że skręcenie w lewo w wiatr może spowodować dryfowanie statku w prawo. Co statki zrobić mieć to bezwładność (i drag): nie można włączyć lub przenieść natychmiast, a raz w ruchu lub skręcania, trochę czasu i siły, aby zatrzymać. Nadal masz +1.
Ilmari Karonen,
Bardzo dziękuję za odpowiedź!!! :) jesteś moim bohaterem!
DavidT,
@DavidT Zastanów się, czy możesz zaznaczyć swoją odpowiedź jako zaakceptowaną, jeśli był w stanie rozwiązać problem w zadowalający sposób. :)
MA
-2

System siatkowy Unity Nav prawdopodobnie zrobiłby to, co chcesz, trochę pobawiając się wartościami agenta nawigacyjnego.

Nav Meshes są dość proste w użyciu. I tylko do użytku w konfiguracji z góry na dół (lub przynajmniej dostępny tylko dla ruchu x / z)

Instrukcja Unity Strona dotycząca konfiguracji siatki nawigacyjnej

Zasadniczo możesz użyć dowolnej siatki kształtów, aby upiec obszar nawigacji, a także dodać agentów nawigacyjnych do swoich obiektów i pozwolić im znaleźć ścieżki wokół siatki nawigacyjnej

ProtoJazz
źródło
Brakuje mi również odpowiedzi Draco18s w tym zakresie. Jednak twoja nie jest prawdziwą odpowiedzią, a raczej komentarzem.
Nikt
2
To dobra sugestia, ale aby być dobrą odpowiedzią, potrzebuje wsparcia i informacji na temat wdrażania. Dodaj informacje dotyczące konfigurowania siatek nawigacyjnych, aby była to dobra odpowiedź. Myślę, że to właśnie próbują powiedzieć
powyżsi komentatorzy