Pracuję nad ulepszeniem wyszukiwania ścieżek dla wrogów mojej gry. W tej chwili po prostu stale poruszają się w kierunku dokładnej pozycji gracza, obliczając kąt między sobą a graczami i poruszając się w tym kierunku. Mam również algorytm uciekający, który zapobiega gromadzeniu się wrogów na sobie, dzięki czemu będą się grupować, a nie przenikać.
Jednak teraz, gdy dodałem mapę opartą na kafelkach, potrzebuję wrogów, aby mogli także na przykład omijać przeszkody i ściany. Początkowo próbowałem dodać wartość separacji do płytek „niepodlegających chodzeniu”, aby algorytm flokowania traktował ściany i przeszkody jako obiekty, z których można się oddalić. Muszę jeszcze ustalić, czy jest to wykonalne, ponieważ mój pierwszy test wykazał, że wrogowie uderzają w niewidzialną „ścianę”, w której nie ma płytek, na których nie można chodzić, ale z jakiegoś powodu uderzają ją i zaczynają szaleć.
Zastanawiałem się, czy obliczenie ścieżki do gracza za pomocą A * może być zbyt trudne, a następnie użyć algorytmu flokowania, aby zapobiec zbijaniu się. Początkowo moja gra miała być strzelanką opartą na falach, ale zamiast tego zdecydowałem, że będę oparty na poziomie w stylu Hotline Miami, więc prawdopodobnie będę miał mniej wrogów, z sporadyczną hordą, i po prostu stworzę je silniejsze.
Czy to realne rozwiązanie? Używam Java z Slick2D jako moim silnikiem gry. A może istnieje lepsze rozwiązanie / algorytm, który rozwiązuje oba te problemy?
źródło
Odpowiedzi:
To brzmi jak przypadek użycia Flow Fields.
W tej technice wykonujesz pojedyncze zapytanie identyfikujące ścieżkę na zewnątrz od obiektów gracza, zaznaczając każdą napotkaną komórkę komórką, z której do niej dotarłeś.
Jeśli wszystkie kafelki / krawędzie mają taki sam koszt przejścia, możesz użyć prostego wyszukiwania w pierwszej kolejności. W przeciwnym razie działa algorytm Dijkstry (jak A * bez celu / heurystyka).
Tworzy to pole przepływu: tabela odnośników, która łączy każdą komórkę z następnym krokiem w kierunku najbliższego obiektu gracza z tej pozycji.
Teraz twoi wrogowie mogą spojrzeć na swoją bieżącą pozycję w polu przepływu, aby znaleźć następny krok na swojej najkrótszej, omijającej przeszkody ścieżce do najbliższego obiektu gracza, bez potrzeby wykonywania własnych zapytań.
To skaluje się coraz lepiej, im więcej wrogów masz w stadzie. Dla pojedynczego wroga jest droższy niż A *, ponieważ przeszukuje całą mapę (choć możesz wyjść wcześniej, gdy dotrzesz do wszystkich agentów szukających ścieżki). Ale gdy dodajesz kolejnych wrogów, mogą oni dzielić coraz większy koszt poszukiwania ścieżki, obliczając dzielone segmenty ścieżki raz, a nie w kółko. Uzyskujesz także przewagę dzięki temu, że BFS / Dijkdtra są prostsze niż A * i zazwyczaj tańsze do oceny w odniesieniu do kontrolowanej komórki.
Dokładnie tam, gdzie dochodzi do progu rentowności, od indywidualnego A *, który jest tańszy, do A * z zapamiętywaniem, który jest tańszy (gdzie ponownie wykorzystujesz niektóre wyniki dla zapytania szukającego ścieżki w przeszłości, aby przyspieszyć następny), do pól przepływu taniej, będzie zależeć od twojej implementacji, liczby agentów i wielkości twojej mapy. Ale jeśli kiedykolwiek zaplanujesz duży rój wrogów zbliżających się z wielu kierunków w ograniczonym obszarze, jedno pole przepływu będzie prawie na pewno tańsze niż iterowane A *.
Jako skrajny przykład możesz zobaczyć tutaj wideo z 20 000 agentów jednocześnie szukających ścieżki na stosunkowo małej siatce .
źródło
A * nie jest ciężkie pod względem wydajności. Do tej sytuacji podszedłbym, zmieniając algorytmy. Od czasu do czasu wykonuj A * i sprawdzaj, czy następny krok jest wolny, czy potrzebujesz uciec.
Na przykład śledź odległość graczy od lokalizacji docelowej A *, jeśli jest ona powyżej progu, ponownie oblicz *, a następnie po prostu wykonaj ruchy aktualizacji. Większość gier wykorzystuje kombinację punktów na drodze, np. Uproszczoną siatkę do wyszukiwania ścieżek i logikę, która obsługuje ruch między punktami za pomocą algorytmów sterowania unikaniem za pomocą raycast. Moim zdaniem agenci próbują biec do odległego punktu, manewrując wokół przeszkód w ich pobliżu.
Najlepiej jest tu pracować z automatami skończonymi i przeczytać książkę Matta Bucklanda „Programowanie gry AI według przykładu”. Książka oferuje sprawdzone techniki rozwiązywania problemów i szczegółowe informacje na temat wymaganej matematyki. Kod źródłowy z książki jest dostępny w Internecie; książka jest w C ++, ale niektóre tłumaczenia (w tym Java) są dostępne.
źródło
Nie tylko jest to wykonalne, ale sądzę, że dokonano tego w komercyjnej grze z lat 90. - BattleZone (1998).
Ta gra miała jednostki 3D z wolnym ruchem nie opartym na płytkach i bazową konstrukcją opartą na płytkach.
Tak to wyglądało:
Po pierwsze, A * lub coś podobnego (prawdopodobnie odmiana A * ze ścisłymi limitami długości ścieżki, którą może znaleźć, więc nigdy nie zajmuje zbyt wiele zasobów, ale nie zawsze znajduje ścieżkę do celu) służyłby do znalezienia drogi dla poduszkowca, aby dostać się do miejsca docelowego bez utknięcia w przeszkodach wyłożonych płytkami.
Następnie czołg latałby wokół wyznaczonego miejsca, jakby był przyciągany do środka pobliskiej płytki na swojej drodze i odpychany przez przeszkody, inne pobliskie czołgi itp.
źródło