Zajmuję się tworzeniem kosmicznej gry 2D bez tarcia i bardzo łatwo mi zrobić celującą rakietę naprowadzającą. Jestem ciekawy strategii anty-orbitujących.
Prostym przykładem jest pocisk naprowadzający, który po prostu przyspiesza bezpośrednio w kierunku celu. Gdyby ten cel poruszał się prostopadle do trajektorii pocisku, a następnie zatrzymałby się, przyspieszenie pocisku w kierunku celu nie wystarczyłoby do pokonania własnej prędkości, a pocisk mógłby zostać skierowany na orbitę wokół celu, jak pokazano:
- W ramce 1 pocisk zmierza prosto do celu, bez problemów.
- W ramce 2 cel przesunął się na nową pozycję, jak pokazano. Pocisk kontynuuje przyspieszenie bezpośrednio w kierunku celu (na czerwono), jednocześnie nadal poruszając się w kierunku, w którym cel był (na czarno) ze względu na swoją istniejącą prędkość.
- W ramce 3 prędkość pocisku nadal przenosi pocisk wokół boku celu (czarny), podczas gdy wektor przyspieszenia desperacko próbuje przyciągnąć pocisk w kierunku celu.
- W ramkach 4 i późniejszych pocisk spada na potencjalnie stabilną orbitę wokół celu i nigdy nie osiąga swojego celu. Czarne strzałki wskazują wektor prędkości, podczas gdy czerwone linie wskazują wektory przyspieszenia w tym samym momencie.
Biorąc pod uwagę, że w przestrzeni kosmicznej nie występuje tarcie, nic nie może spowolnić prędkości pocisku i zawalić orbitę. Możliwym rozwiązaniem byłoby celowanie „za” celem, a to spowodowałoby zamknięcie orbity, ale jak to się robi z punktu widzenia programowania?
Jak sprawić, by rakieta naprowadzająca osiągnęła cel?
Odpowiedzi:
Przede wszystkim należy wykonać wszystkie obliczenia dotyczące tego, jakie przyspieszenie zastosować w układzie odniesienia pocisku (tam, gdzie pocisk jest nieruchomy i wszystko inne się wokół niego porusza, często nazywane także „współrzędnymi obiektu” lub „lokalnymi współrzędnymi” w silnikach gry, chociaż w naszym przypadku chcemy, aby prędkość była dokładnie równa zeru).
Ideą nie jest zatem dążenie do celu, ale dążenie do miejsca, w którym cel będzie w przewidywanym czasie uderzenia. Ogólny algorytm wygląda następująco:
Oszacuj, ile czasu zajmie dotarcie pocisku do celu. Jeśli cel leci bezpośrednio na niego (pamiętaj, że pocisk jest nieruchomy ), może być tak prosty jak obliczenie odległości / prędkości , w innych przypadkach może być bardziej skomplikowany. Jeśli cel może spróbować uniknąć, i tak nie będziesz w stanie dokonać dokładnego oszacowania, więc nie jest zbyt precyzyjne.
Zakładając stałą prędkość (oszacowanie 1 stopnia) lub stałe przyspieszenie (oszacowanie 2 stopnia) celu, obliczyć, gdzie będzie w przewidywanym czasie powyżej.
Oblicz przyspieszenie, które spowoduje, że pocisk znajdzie się w przybliżeniu w tym samym miejscu w tym samym czasie.
Ponownie rzutuj przyspieszenie z układu odniesienia pocisku na globalny, użyj tego.
Ważną kwestią jest oszacowanie czasu w trudnym boisku i nie zapominanie o możliwościach przyspieszenia pocisku. Na przykład lepszym oszacowaniem dla „celu jest tuż przed nami i lecącego w naszym kierunku” byłoby rozwiązanie równania.
odległość = prędkość x czas + 1/2 x przyspieszenie x czas 2
... do czasu (użyć negatywny prędkości dla obiektów latających prosto z dala od pocisku) z roztworem szukasz przy użyciu standardowego wzoru kwadratowego będąc ...
czas = (√ ( prędkość 2 + 2 x przyspieszenie x odległość ) - prędkość ) / przyspieszenie
Dodanie dodatkowych parametrów - na przykład przeciągnięcia - szybko zamienia to w równania różniczkowe bez rozwiązań algebraicznych. Właśnie dlatego nauka rakiet jest tak trudna.
źródło
@Martin Sojka powiedział ci już, co masz robić. Zamiast poprawić jego reakcję, chcę zaproponować ci inne, prostsze podejście: DELOCK
Jak powiedziałem w Prognozowanej trajektorii pojazdu? , obiekty o ograniczonych możliwościach sterowania „rzutują” kilka cienia: dwa obszary, do których nie można dotrzeć poprzez bezpośrednie sterowanie (torus i hypertorus w większych wymiarach).
Kiedy zobaczysz, że twój cel wkracza w jeden z takich cieni sterujących, możesz przestać naprowadzać swój cel i utrzymywać inny kierunek przez ograniczony czas.
Wyzwalacz blokujący można łatwo obliczyć, przybliżając tori za pomocą (podwójnego) stożka *:
Musisz po prostu obliczyć iloczyn skalarny między (znormalizowanym) wektorem kierunku a docelowym wektorem przemieszczenia ( Cel - Obiekt / | Cel - Obiekt |).
Gdy iloczyn skalarny osiągnie zero, kierunek docelowy staje się prostopadły do kierunku prowadzącego do kołowej trajektorii **. Kiedy cel wpada w region niebieskozielony, możesz odwrócić kierunek sterowania, aby umieścić go poza nieosiągalnym obszarem i wrócić do bazowania.
* Szczerze mówiąc, nie jest to stożek ... to inny rodzaj powierzchni rządzonej generowanej przez (pół) obrót dwóch nierównoległych linii wokół osi przechodzącej przez przecięcie i prostopadłej do linii dwusiecznej; Rzut na płaszczyznę 2D jest taki sam jak podwójny stożek, ale oś obrotu jest prostopadła do osi, która generuje stożek.
** Jest mało prawdopodobne, aby trajektoria ta była okrągła, eliptyczna, a nawet zamknięta. Są szanse, że trajektoria podąży ścieżką podobną do spirografu (hypotrochoid) w 2D lub nawet innych potworach w 3 i wyższych wymiarach. W każdym razie nie można dotrzeć do środka takich krzywych, które wyglądają jak koła, więc „okrągły” tor.
źródło
Twój system prowadzenia opiera się na założeniu, że przyspieszenie bezpośrednio w kierunku celu ostatecznie spowoduje zderzenie się obiektów. Ponieważ to założenie jest fałszywe, wytyczne AI oparte na tym założeniu również są nieskuteczne.
Przestań więc przyspieszać bezpośrednio w kierunku celu. Dodaj trochę logiki, aby wykryć, czy pozycja celu jest nieco prostopadła do kierunku ruchu pocisku. Jeśli tak, to pocisk musi przyspieszyć w kierunku celu, ale także spowolnić swój ruch do przodu. Zamiast kierować się bezpośrednio w stronę celu, kieruje się kierunkiem przyspieszenia, tak że bieżąca prędkość w jego kierunku ruchu jest spowalniana.
Będziesz także potrzebować spustu, aby upewnić się, że nie jedziesz zbyt wolno. Dodaj więc prędkość progową, tak że jeśli znajdziesz się poniżej tego progu, przestaniesz promować.
I ostatnia rzecz: żaden system prowadzenia nie będzie idealny. Powodem, dla którego pociski mogą przechwytywać cele w prawdziwym życiu, jest to, że cele poruszają się znacznie wolniej niż same pociski, a cele nie są szczególnie zwinne (mówiąc względnie). Jeśli twoje pociski nie będą wiele razy szybsze niż ścigane przez siebie cele, wtedy będą bardzo tęsknić.
źródło
Najprostszą i najbardziej zaawansowaną metodą do tego celu w grach (i prawdziwym życiu) jest Nawigacja proporcjonalna.
Pod stałym łożyskiem Zmniejszenie zakresu (CBDR) logikę, gdy dwa obiekty (rakietowe i docelowe) podróżują w tym samym kierunku, bez zmian w zwykłej osi między sobą, że będą kolidować.
Linia celownicza (LOS) to wyobrażona linia między pociskiem a celem - wektor między pozycją pocisku a pozycją celu. Szybkość zmiany kątowej tego LOS to szybkość rotacji LOS.
Kiedy prędkość obrotu LOS staje się zerowa, wówczas linia wzroku już się nie zmienia - dwa obiekty znajdują się teraz na kursie kolizyjnym. Myśl o sobie jak o gonieniu kogoś podczas gry w piłkę nożną. Jeśli poprowadzisz go w taki sposób, że jego ciało wygląda na „zamrożone” w polu widzenia (linia wzroku między tobą a nim już się nie zmienia), zderzysz się z nim, dopóki utrzymasz przyspieszenie biegu, aby jego ciało wydawało się zamrożone w Twój widok.
Zgodnie z nawigacją proporcjonalną (PN) pocisk przyspiesza „N” razy szybciej niż szybkość rotacji LOS. Zmusi to pocisk do prowadzenia celu, dopóki wskaźnik rotacji LOS nie wyniesie zero - to znaczy, pocisk i cel wydają się zamrożone w stanie, gdy linia wzroku już się nie zmienia - są teraz na kursie kolizyjnym. Zmienna „N” jest znana jako stała nawigacji (stały mnożnik).
Komenda naprowadzania pocisku powinna być wydana w następujący sposób:
Przyspieszenie = prędkość zamykania * N * Szybkość LOS
Szybkość LOS można łatwo wyliczyć, mierząc wektor LOS (pozycja docelowa - pozycja pocisku) i przechowując jego zmienną. Wektor LOS z nowej ramki (LOS1) jest odejmowany przez wektor LOS od starej ramki (LOS0), aby wygenerować deltę LOS - teraz masz prymitywną prędkość obrotową LOS.
Aby uprościć prędkość zamykania, możesz po prostu użyć obecnego wektora LOS na jego miejscu, a zatem:
Przyspieszenie = (target_pos - pocisk_pos) * LOS_delta * N
N jest stałą nawigacji - w prawdziwym świecie jest zwykle ustawiana między 3 a 5, ale rzeczywista możliwa do wykorzystania liczba w grze jest w pewnym stopniu zależna od częstotliwości próbkowania, przy której uzyskujesz współczynnik / delta LOS. Wypróbuj losową liczbę (zacznij od 3) i zwiększ ją do 1500, 2000 itd., Aż zobaczysz pożądany efekt wiodący w grze. Zauważ, że im wyższa stała nawigacji, tym szybciej pocisk zareaguje na zmiany prędkości LOS na początku lotu. Jeśli twój model symulacji rakiety naprowadzającej jest nieco realistyczny, nadmierna stała nawigacji może przeciążyć możliwości aerodynamiczne pocisku, więc powinieneś użyć zrównoważonej liczby opartej na próbach i błędach.
źródło
Jak wskazują inne odpowiedzi Martina i Nicola, prawdopodobnie chcesz skierować swój pocisk nie bezpośrednio na cel, ale w sposób, który spowoduje, że zderzy się on z celem w późniejszym czasie. Jednak metoda opisana przez Martina jest skomplikowana, a metoda opisana przez Nicola jest nieefektywna.
Prostszym sposobem - ale nadal dość wydajnym - kierowania pociskiem jest dostosowanie jego kąta zgodnie ze zmianą kąta między pociskiem a celem. Na każdym tyknięciu obliczasz kąt od pocisku do celu i porównujesz go z kątem z poprzedniego tyknięcia. Różnica jest dokładną różnicą, którą chcesz zrobić pod kątem pocisku. Więc jeśli kąt wynosił 0,77 w jednym tiku i 0,75 w następnym, chcesz wyregulować kąt pocisku o -0,02. Ta metoda jest prosta i dopóki cel znajduje się „przed” pociskiem, jest bardzo wydajny pod względem wybranej trasy. Dotyczy to także dowolnej liczby wymiarów, nie tylko 2d.
Pamiętaj jednak:
Ta metoda zrywa się, jeśli pocisk i cel mają dokładnie taką samą prędkość i poruszają się równolegle. Cóż, nadal teoretycznie wyznacza kurs kolizji dla pocisku, zajmuje to nieskończenie dużo czasu :) w praktyce pocisk powinien zawsze być szybszy niż cel, ale jeśli mają identyczną prędkość, należy dodać skrzynkę narożną, aby określić, czy są równoległe .
Metoda zostaje zerwana, jeśli cel i pocisk lecą dokładnie na tej samej linii, ale w przeciwnych kierunkach. To nie może się zdarzyć w prawdziwym świecie, ale nie jest zbyt rzadkie w dyskretnej grze. Musisz dodać sprawdzanie wielkości liter w powyższym algorytmie, aby to sprawdzić.
Jeśli twój pocisk ma ograniczoną zdolność do obracania się, po prostu spraw, aby wykonał maksymalny obrót za każdym razem, gdy musi obrócić więcej. Tak długo, jak pocisk jest wystarczająco daleko, nadal będzie działał. Jeśli jest za blisko, zobacz ostatnią kulę.
Pamiętaj o wyrozumiałości podczas sprawdzania kolizji. W prawdziwym świecie wiele pocisków polega na głowicy bojowej, aby stworzyć „strefę zabójstwa”, więc muszą jedynie zbliżyć się do celu, a nie zderzyć się z nim.
Wreszcie, w praktyce pocisk może nadal chybić , co przywraca nas do pierwotnego pytania. Myślę, że dobrym sposobem jest rzeczywiście wyłączenie bazowania dla kilku tyknięć, pozostawienie go na pewien dystans, a następnie ponowne bazowanie. Myślę, że metoda zaproponowana przez fxiii do identyfikacji martwych stref jest świetnym sposobem na wykrycie, kiedy trzeba wyłączyć bazowanie.
źródło
Kilka prostych opcji, które okazały się „wystarczająco dobre” dla gier, nad którymi pracowałem w przeszłości:
1) Jeśli rozdzielczość sceny, na którą patrzysz, pozwala na to, wtedy obiekt może eksplodować, gdy znajdzie się w pobliżu celu (tak uważam, że w większości przypadków pociski samonaprowadzające faktycznie działają w każdym przypadku). Jeśli twój zasięg na orbicie jest około dwa razy większy od obiektu, prawdopodobnie nie zadziała to dla ciebie, ponieważ wyglądałoby to źle.
Jeśli twoim ostatecznym celem w twoim rozwiązaniu jest po prostu upewnienie się, że twój pocisk trafi w cel, to jestem za tym, aby Po prostu trafił w cel. Znowu będzie to zależeć tylko od wyglądu rozwiązania.
2) Jeśli stwierdzisz, że twój pocisk jest ustawiony pod kątem prostym do celu, może to być punkt, w którym blokada „pęka”, a pocisk po prostu porusza się prosto, chyba że cel ponownie znajdzie się „przed” pociskiem.
Zawsze preferuję proste rozwiązania, gdy tylko jest to możliwe. Jeśli tworzysz grę, w której wystrzeliwany pocisk jest tylko jedną z używanych broni, prawdopodobnie uda Ci się uciec, ponieważ gracze prawdopodobnie wystrzelą salwę, a następnie szybko powrócą do swoich stałych broni. Jeśli jednak wykonujesz symulację pocisku, to wyraźnie jedna z pozostałych odpowiedzi jest lepszym wyborem.
Mam nadzieję że to pomoże.
źródło
Jak już powiedziano, powinieneś wycelować pocisk w miejsce, w którym powinien znajdować się cel, kiedy tam dotrzesz, a nie w miejsce, w którym cel jest teraz. To powstrzyma MOJE pociski przed wejściem na orbitę, ale orbita jest nadal możliwa, jeśli cel unika dokładnie. Jest to uzasadniona taktyka stosowana przez pilotów samolotów do unikania nadlatujących pocisków - ponieważ pocisk leci znacznie szybciej niż ty, będzie miał większy promień skrętu, a ostry jink w odpowiednim momencie spowoduje jego przejście. (Chociaż nadal możesz być narażony na detonację zbliżeniową).
Ponieważ mamy do czynienia z pociskiem, który może nadal śledzić i nadal pchać, dostajesz sytuację na orbicie, jeśli cel ucieknie w jedną ze stref, o których mówi post FxIII.
Nie zgadzam się jednak z jego rozwiązaniem tego problemu. Zamiast tego zaprogramowałbym odpowiednio pociski:
jeśli pocisk pchnie się pod kątem 90 stopni do linii ruchu w celu obrotu o 360 stopni, jesteś na orbicie. Ustaw ciąg do 120 stopni od linii ruchu. Orbita pocisku rozszerzy się, ponieważ nie obraca się tak mocno, ale pocisk również zwolni, umożliwiając mu lepsze manewrowanie. Gdy zasięg do celu otworzy się na 1,25x średnicę martwej strefy (zauważ, że średnica ta jest oparta w prosty sposób i tylko na prędkości pocisku, nie jest wymagane skomplikowane obliczenie w czasie wykonywania), pocisk wraca do normalnego zachowania podczas śledzenia.
Alternatywnie użyj głupszych głów poszukiwaczy - gdy zasięg do celu przestanie odliczać, detonujesz.
źródło
Wiem, że to jest starodawne pytanie, ale myślę, że w odpowiedziach udzielonych do tej pory coś pominęło. W pierwotnym pytaniu pocisk (lub cokolwiek innego) miał przyspieszyć w kierunku pozycji celu. Kilka odpowiedzi wskazało, że było to błędne, i powinieneś przyspieszyć w kierunku, w którym twoim zdaniem będzie cel w późniejszym czasie. Jest lepiej, ale nadal źle.
To, co naprawdę chcesz zrobić, to nie przyspieszać w kierunku celu, ale zbliżać się do celu. Sposobem na przemyślenie tego jest ustawienie pożądanej prędkości skierowanej na cel (lub rzut lokalizacji celu), a następnie ustalenie, jakie przyspieszenie najlepiej zastosować (biorąc pod uwagę wszelkie ograniczenia, jakie masz, tj. Pocisk prawdopodobnie nie może przyspieszyć bezpośrednio w odwrotnej kolejności), aby osiągnąć pożądaną prędkość (pamiętając, że prędkość jest wektorem).
Oto sprawdzony przykład, który zaimplementowałem dziś rano, w moim przypadku dla sztucznej inteligencji gracza w sportowej grze symulacyjnej, w której gracz próbuje ścigać przeciwnika. Ruch jest regulowany przez standardowy model „kick-drift”, w którym przyspieszenia są stosowane na początku pomiaru czasu w celu aktualizacji prędkości, a następnie obiekty dryfują z tą prędkością przez czas trwania pomiaru czasu.
Chciałbym opublikować pochodną tego, ale stwierdziłem, że nie ma obsługiwanego znacznika matematycznego na tej stronie. Gwizd! Musisz tylko zaufać, że jest to optymalne rozwiązanie, zważywszy na to, że nie mam ograniczeń co do kierunku przyspieszenia, czego nie ma w przypadku obiektu typu pocisk, więc wymagałoby to dodatkowych ograniczeń.
Kod jest w Pythonie, ale powinien być czytelny na dowolnym tle języka. Dla uproszczenia zakładam, że każdy krok ma długość 1 i wyrażam prędkość i przyspieszenie w odpowiednich jednostkach, aby to odzwierciedlić.
Zauważ, że funkcja atan2 (a, b) oblicza odwrotną tan a / b, ale zapewnia, że kąty znajdują się we właściwej ćwiartce koła, co wymaga znajomości znaku zarówno a, jak i b.
W moim przypadku, gdy już mam przyspieszenie, stosuję to, aby zaktualizować prędkość o
Sprawdzam też nową prędkość względem prędkości maksymalnej zależnej od gracza i ograniczam ją. W przypadku pocisku, samochodu lub czegoś o maksymalnej prędkości obrotu (w stopniach na tyknięcie) możesz po prostu spojrzeć na aktualny kąt ruchu w stosunku do obliczonego ideału, a jeśli ta zmiana jest większa niż dozwolona, po prostu zmień kąt o jak najwięcej w kierunku ideału.
Dla każdego, kto jest zainteresowany wyprowadzeniem tego, zapisałem odległość między graczem a celem po upływie czasu, pod względem pozycji początkowej, prędkości, prędkości przyspieszenia i kąta przyspieszenia, a następnie wziąłem pochodną w odniesieniu do kąta przyspieszenia. Ustawienie tej wartości na zero powoduje, że minima odległości gracz-cel po odmierzeniu czasu są funkcją kąta przyspieszenia, co dokładnie chcemy wiedzieć. Co ciekawe, mimo że szybkość przyspieszenia była pierwotnie w równaniach, anuluje się, uniezależniając optymalny kierunek od tego, jak bardzo jesteś w stanie przyspieszyć.
źródło
Używasz stałej prędkości skrętu. To właśnie powoduje ładną idealnie okrągłą orbitę.
Bardziej realistycznym podejściem dla systemu prowadzenia byłoby zróżnicowanie prędkości skrętu z odwrotną odległością docelową (mniejsza odległość -> większa prędkość skrętu). Dałoby to spiralę zamiast orbity i gwarantowałoby kolizję z wolniejszym celem.
Daje również znacznie bardziej realistyczną ścieżkę lotu. Stała prędkość skrętu jest nienaturalnie idealna. Możesz również dodać losowe zmiany do prędkości skrętu, aby zasymulować turbulencje. Ponownie, o wiele bardziej realistyczny i może faktycznie uniknąć scenariuszy orbitujących w stanie ustalonym.
Nie potrzeba równań częściowych.
źródło