A * hallazgo de ruta de malla de navegación

15

Así que he estado haciendo este juego java 2D de arriba hacia abajo en este marco llamado Greenfoot y he estado trabajando en la IA para los chicos con los que lucharás. Quiero que puedan moverse por el mundo de manera realista, así que pronto me di cuenta, entre otras cosas, que necesitaría algún tipo de búsqueda de caminos.

He hecho dos prototipos A *. Uno está basado en la cuadrícula y luego hice uno que funciona con puntos de referencia, así que ahora necesito encontrar una forma de llegar desde un "mapa" en 2D de los obstáculos / edificios a un gráfico de nodos desde el que pueda hacer un camino. La búsqueda de ruta real parece estar bien, solo mis listas abiertas y cerradas podrían usar una estructura de datos más eficiente, pero llegaré a eso si es necesario.

Tengo la intención de utilizar una malla de navegación por todas las razones descritas en esta publicación en ai-blog.net . Sin embargo, el problema al que me he enfrentado es que lo que A * piensa es que la ruta más corta desde los centros / bordes del polígono no es necesariamente la ruta más corta si viaja a través de cualquier parte del nodo. Para tener una mejor idea, puede ver la pregunta que hice en stackoverflow .

Obtuve una buena respuesta con respecto a un gráfico de visibilidad. Desde entonces compré el libro ( Geometría computacional: algoritmos y aplicaciones ) y leí más sobre el tema, sin embargo, todavía estoy a favor de una malla de navegación (ver " Gestión de la complejidad " de las notas de Amit sobre la búsqueda de caminos ). (Como nota al margen, tal vez podría usar Theta * para convertir varios puntos de referencia en una línea recta si el primero y el último no están ocultos. O cada vez que retrocedo, verifique el punto de referencia antes de la última para ver si puedo ir directamente desde que a esto)

Entonces, básicamente, lo que quiero es una malla de navegación donde una vez que lo haya sometido a un algoritmo de embudo (por ejemplo, este de Digesting Duck ) obtendré la verdadera ruta más corta, en lugar de obtener una que sea la ruta más corta siguiendo solo de nodo a nodo, pero no es el más corto, dado que puede atravesar algunos polígonos y omitir nodos / bordes.

Ah, y también quiero saber cómo sugiere almacenar la información relativa a los polígonos. Para el ejemplo del prototipo de waypoint que hice, solo tenía cada nodo como un objeto y almacené una lista de todos los otros nodos a los que podría viajar desde ese nodo, supongo que eso no funcionará con polígonos. ¿Y cómo puedo saber si un polígono es abierto / transitable o si es un objeto sólido? ¿Cómo almaceno qué nodos forman el polígono?

Finalmente, para que conste: quiero programar esto desde cero a pesar de que ya hay otras soluciones disponibles y no tengo la intención de (re) usar este código en otra cosa que no sea este juego, por lo que no importa inevitablemente será de mala calidad.

polvo enojado
fuente
No estoy seguro, pero estos enlaces pueden ayudar: gamedev.stackexchange.com/questions/1327/… gamedev.stackexchange.com/questions/8087/… también hubo otra pregunta sobre la búsqueda de rutas que no puedo encontrar en este momento , que obtuvo una recompensa y tuvo una muy buena respuesta.
Ali1S232
Sí, en el segundo enlace puede ver mi principal preocupación, el algoritmo A * daría a la ruta alrededor del fondo como la más corta usando puntos medios de borde, pero la ruta alrededor de la parte superior del obstáculo es en realidad la más corta. Quiero saber cómo puedo obtener A * para darme el camino alrededor de la parte superior que luego enderezaré (mediante un algoritmo de embudo, por ejemplo) para obtener el verdadero camino más corto, donde, como si me diera el que está en la parte inferior, entonces incluso si lo enderezo todavía está tomando un desvío.
angrydust
En realidad, acabo de leer el artículo en gamedev.stackexchange.com/questions/8087/… y parece funcionar al encontrar una ruta con A *, luego calcular su costo real con un algoritmo de embudo modificado y luego encontrar otra ruta y calcularlo costo real de nuevo y ver si es más corto que el otro. Se repite hasta que sabe que ha encontrado la ruta más corta. De hecho, esto resuelve mi problema, sin embargo, parece que será bastante lento, ya que está repitiendo tanto el enderezado como la búsqueda del camino, lo que sería bastante costoso.
angrydust
Almacenamiento de polígonos: solo almacene los polígonos visibles, o asocie una etiqueta con cada polígono (recuerde que cada polígono deberá ser una lista circular de vértices); de manera similar con los nodos, puede almacenar la identificación del polígono del que provienen, pero no debería necesitar decirle esto: es el almacenamiento de datos elemental. Finalmente, ¿por qué te importa el verdadero camino más corto? Tu juego puede correr lento o puedes tener caminos ligeramente incorrectos: elige uno. La obtención de la ruta más corta verdadera REQUIERE una búsqueda de amplitud completa (al menos sobre un gráfico de nodo).
Jonathan Dickinson el
@JonathanDickinson Sé que no necesito un camino que será 100% exacto hasta el último píxel, y sé que puede utilizar un * para producir caminos que serán como máximo p admisible. La cosa está yendo muy lejos en un obstáculo tan claramente, como en mi pregunta anterior sobre desbordamiento de pila o en gamedev.stackexchange.com/questions/8087/… es simplemente demasiado. ¡No puedo dejar que mi IA camine de esa manera alrededor de un obstáculo!
angrydust

Respuestas:

14

Aconsejaría que, incluso si va a escribir todo su propio código, descargue Recast y cree la aplicación de muestra, ya que tiene visualizaciones que muestran la malla de navegación generada y le permite probar la búsqueda de ruta con un simple punto y haga clic interfaz. Puedes aprender mucho solo jugando con eso.

Como ya se ha dado cuenta, hay dos pasos para producir una ruta atractiva: el buscador de rutas A * y luego el posterior procesamiento posterior que incluye el enderezado de la ruta (la eliminación de cualquier giro no necesario para evitar obstáculos) y posiblemente también el adición de curvas en los puntos de inflexión.

Encontrar el camino

Has dominado la parte A *, lo cual es genial. También ha observado que A * no siempre encontrará el camino más recto. Es crucial entender que esto se debe a que A * es un algoritmo para encontrar la ruta más corta a través de un gráfico (siendo un concepto matemático donde los nodos no tienen dimensión) cuando lo aplica a una malla, debe mapear los nodos para mallar elementos de alguna manera.

Lo más obvio es navegar del punto central del polígono al punto central y basar el costo en esta distancia, pero esto tiene algunos problemas. Una es que no siempre encontrará la ruta geométricamente más corta y la segunda es que si intenta seguir la ruta que calculó allí, notará que una línea recta desde un centro al siguiente puede cruzar un polígono que no está t parte de la ruta (y podría no ser navegable en absoluto). No es una forma horrible de costar el recorrido del gráfico mientras se realiza A *, pero claramente no es adecuado para ningún propósito transversal.

La siguiente solución más simple es realizar A * de borde a borde a través de la malla. Encontrará esto más simple para pensar si imagina que en lugar de un nodo por polígono, tiene uno por borde por polígono. Por lo tanto, su ruta va desde su punto de inicio hasta el borde más cercano, se cruza justo dentro del borde del polígono adyacente y luego justo dentro del borde siguiente en el mismo polígono y así sucesivamente. Esto produce el camino más corto con más frecuencia y también tiene la ventaja de ser transitable si no desea realizar un paso de enderezado del camino.

Enderezar camino

El algoritmo utilizado en Detour (la biblioteca de navegación que acompaña a Recast) es bastante simple. Debe observar que solo enderezará la ruta dentro de los límites de los polígonos encontrados durante la búsqueda A *. Como tal, si eso no encuentra el camino más estrecho alrededor de un obstáculo, tampoco obtendrá un camino apretado después de ejecutar ese algoritmo. En la práctica, las redes de navegación producidas por la refundición tienden a tener un único polígono que puede atravesar cuando navega por un punto de estrangulamiento (el punto más cercano entre dos obstáculos) y, por lo tanto, A * siempre producirá una lista de nodos que están tan cerca del obstáculo como posible. Si está utilizando mosaicos como la malla de navegación, este no será el caso y este algoritmo muy simple insertará giros espurios.

El algoritmo de enderezamiento de ruta de desvío no es del todo complejo (O) porque cuando determina que necesita insertar un giro, lo inserta en el punto donde apretó el embudo hacia la izquierda por última vez (al girar a la izquierda y viceversa) y luego comienza a trazar los nodos desde ese punto nuevamente.

Si desea enderezar el camino fuera de los polígonos que forman parte de la ruta A *, las cosas se vuelven mucho más complejas. Deberá implementar una rutina de proyección de rayos que pueda probar si dos puntos en su navegador se pueden ver (debe tener esto de todos modos para que pueda ver si necesita usar A *). Para ello, intersecta el segmento de línea formado por origen-> destino con los bordes de conexión del polígono que contiene el origen, luego prueba los bordes de conexión del polígono que te mueve hacia adentro y así sucesivamente. Si intersecta un borde que no conecta (los llamo bordes de borde), entonces ha chocado con un obstáculo.

Luego puede realizar esta prueba de proyección de rayos cada vez que el algoritmo de canalización determine que necesita insertar un turno para ver si realmente lo hace, pero creo que tendrá que seguir realizando esa prueba en cada nodo hasta que inserte un turno (en en qué punto puede volver al algoritmo de embudo simple). Eso va a ser costoso, haciendo que el camino se enderece aproximadamente O (n ^ 2).

Representando el navmesh

Puede representar su malla como una matriz de clases de polígonos. La clase de polígono podría ser tan simple como una matriz de vértices y una matriz de referencias al polígono adyacente para cada borde si hay una. Por supuesto, probablemente pueda pensar en formas de almacenarlo de manera más compacta. Dado que un vértice generalmente es compartido por varios polígonos, es normal tener una gran variedad de vértices y luego hacer que cada polígono almacene índices en esa matriz. Dependiendo de las características de su navegador, es posible que tenga un número promedio de bordes de conexión que es solo el 50% o menos del número de bordes. En ese caso, es posible que desee almacenar un enlace a otro polígono y el índice del borde en lugar de almacenar un enlace para cada borde. También le recomiendo que almacene el índice del polígono en la matriz de polígonos de navmesh en lugar de utilizar una referencia de clase.

U62
fuente
Acabo de tener una breve lectura de esto, pero entiendo que nunca debes usar el cuadrado de la distancia (o no la raíz cuadrada) para A *: theory.stanford.edu/~amitp/GameProgramming/…
angrydust
Realmente no estoy preocupado acerca de cómo seguir realmente el camino enderezando el cajero automático, lo que me preocupa es lo que dices: "Debes observar que solo enderezará el camino dentro de los límites de los polígonos encontrados durante la búsqueda A * Como tal, si eso no encuentra el camino más cerrado alrededor de un obstáculo, tampoco obtendrá un camino apretado después de ejecutar ese algoritmo ".
angrydust
Quiero tener una malla de navegación donde A * siempre encontrará el camino que una vez enderezado es el más corto, independientemente del costo de viajar a través de vértices / puntos medios. Aprecio que esto se pueda hacer con el gráfico de visibilidad, pero quiero usar un navegador porque tiene muchos otros beneficios y porque la complejidad de un gráfico de visibilidad puede crecer muy rápidamente: theory.stanford.edu/~amitp/GameProgramming/…
angrydust
@theguywholikeslinux puede usar la distancia euclidiana sqrt(x*x + y*y), pero no la más barata por nodo x*x + y*y.
Jonathan Dickinson el
@ JonathanDickinson Lo sé, de ahí mi punto.
angrydust