Kilka pomysłów na unikanie wyszukiwań, które prowadzą do nieudanych ścieżek:
ID wyspy
Jednym z najtańszych sposobów na szybsze zakończenie wyszukiwania A * jest brak wyszukiwania. Jeśli obszary są naprawdę nieprzejezdne dla wszystkich agentów, zalej każdy obszar unikalnym identyfikatorem wyspy przy obciążeniu (lub w rurociągu). Podczas wyszukiwania ścieżki sprawdź, czy identyfikator wyspy początku ścieżki jest zgodny z identyfikatorem wyspy miejsca docelowego. Jeśli się nie zgadzają, wyszukiwanie nie ma sensu - dwa punkty znajdują się na odrębnych, niepołączonych wyspach. Pomaga to tylko wtedy, gdy dla wszystkich agentów istnieją naprawdę nieprzejezdne węzły.
Ogranicz górną granicę
Ograniczam górną granicę maksymalnej liczby węzłów, które można przeszukiwać. Pomaga to w nieprzerwanym wyszukiwaniu, ale oznacza to, że niektóre bardzo długie wyszukiwania, które są bardzo długie, mogą zostać utracone. Liczba ta musi zostać dostrojona i tak naprawdę nie rozwiązuje problemu, ale zmniejsza koszty związane z długimi poszukiwaniami.
Jeśli odkrywasz, że trwa to zbyt długo , przydatne są następujące techniki:
Zrób to asynchronicznie i ogranicz iteracje
Pozwól, aby wyszukiwanie przebiegało w osobnym wątku lub nieco w każdej ramce, aby gra nie utknęła w miejscu, czekając na wyszukiwanie. Wyświetlaj animację postaci drapiącą się po głowie lub tupiącą stopą, lub cokolwiek odpowiedniego, czekając na zakończenie poszukiwań. Aby to zrobić skutecznie, zachowałbym Stan wyszukiwania jako osobny obiekt i pozwoliłbym na istnienie wielu stanów. Gdy żądana jest ścieżka, weź wolny obiekt stanu i dodaj go do kolejki aktywnych obiektów stanu. W aktualizacji odnajdywania ścieżek ściągnij aktywny element z przodu kolejki i uruchamiaj A *, aż A. zakończy się lub B. zostanie przekroczony pewien limit iteracji. Po zakończeniu ponownie umieść obiekt stanu na liście obiektów stanu swobodnego. Jeśli się nie zakończyło, umieść je na końcu „aktywnych wyszukiwań” i przejdź do następnego.
Wybierz odpowiednie struktury danych
Upewnij się, że używasz odpowiednich struktur danych. Oto jak działa mój StateObject. Wszystkie moje węzły są wstępnie przypisane do skończonej liczby - powiedzmy 1024 lub 2048 - ze względu na wydajność. Używam puli węzłów, która przyspiesza przydzielanie węzłów, a także pozwala mi przechowywać indeksy zamiast wskaźników w moich strukturach danych, które są u16s (lub u8, jeśli mam 255 węzłów max, co robię w niektórych grach). Do wyszukiwania ścieżek używam kolejki priorytetowej dla otwartej listy, przechowując wskaźniki do obiektów Node. Jest zaimplementowany jako plik binarny, a wartości zmiennoprzecinkowe sortuję jako liczby całkowite, ponieważ są one zawsze dodatnie, a moja platforma ma wolne wartości zmiennoprzecinkowe w porównaniu. Używam hashtable dla mojej zamkniętej mapy, aby śledzić odwiedzone węzły. Przechowuje identyfikatory NodeID, a nie Nodes, aby zaoszczędzić na rozmiarach pamięci podręcznej.
Buforuj co możesz
Kiedy po raz pierwszy odwiedzasz węzeł i obliczasz odległość do miejsca docelowego, buforuj go w węźle przechowywanym w obiekcie stanu. Jeśli ponownie wrócisz do węzła, użyj wyniku z pamięci podręcznej zamiast ponownie go obliczać. W moim przypadku pomaga to nie robić pierwiastka kwadratowego na ponownie odwiedzonych węzłach. Może się okazać, że istnieją inne wartości, które można wstępnie obliczyć i buforować.
Inne obszary, które możesz zbadać: użyj dwukierunkowego wyszukiwania ścieżek, aby wyszukiwać z dowolnego końca. Nie zrobiłem tego, ale jak zauważyli inni, może to pomóc, ale nie jest to obojętne. Inną rzeczą na mojej liście do wypróbowania jest hierarchiczne wyszukiwanie ścieżek lub wyszukiwanie ścieżek klastrowych. Jest ciekawy opis w dokumentacji HavokAI Tutaj opisując ich koncepcji klastrów, która jest inna niż HPA * wdrożenia opisanych tutaj .
Powodzenia i daj nam znać, co znajdziesz.