Algunas ideas para evitar búsquedas que resultan en rutas fallidas por completo:
ID de la isla
Una de las formas más económicas de finalizar eficazmente las búsquedas A * más rápidas es no realizar ninguna búsqueda. Si las áreas son realmente impasibles por todos los agentes, las inundaciones llenan cada área con una identificación de isla única en la carga (o en la tubería). Al buscar rutas, verifique si la ID de la isla del origen de la ruta coincide con la ID de la isla del destino. Si no coinciden, no tiene sentido hacer la búsqueda: los dos puntos están en islas distintas y no conectadas. Esto solo ayuda si hay nodos verdaderamente intransitables para todos los agentes.
Límite superior
Limito el límite superior del número máximo de nodos que se pueden buscar. Esto ayuda a que las búsquedas intransitables se ejecuten para siempre, pero significa que se pueden perder algunas búsquedas pasables que son muy largas. Este número necesita ser ajustado, y realmente no resuelve el problema, pero mitiga los costos asociados con búsquedas largas.
Si lo que está encontrando es que está tardando demasiado , las siguientes técnicas son útiles:
Hágalo asíncrono y limite las iteraciones
Deje que la búsqueda se ejecute en un hilo separado o un poco en cada cuadro para que el juego no se detenga esperando la búsqueda. Visualice la animación del personaje rascándose la cabeza o estampando los pies, o lo que sea apropiado mientras espera que finalice la búsqueda. Para hacer esto de manera efectiva, mantendría el estado de la búsqueda como un objeto separado y permitiría la existencia de múltiples estados. Cuando se solicita una ruta, tome un objeto de estado libre y agréguelo a la cola de objetos de estado activo. En su actualización de búsqueda de ruta, extraiga el elemento activo del frente de la cola y ejecute A * hasta que A. se complete o B. se ejecute algún límite de iteraciones. Si está completo, vuelva a colocar el objeto de estado en la lista de objetos de estado libre. Si no se ha completado, colóquelo al final de las 'búsquedas activas' y pase a la siguiente.
Elija las estructuras de datos correctas
Asegúrese de usar las estructuras de datos correctas. Así es como funciona mi StateObject. Todos mis nodos están asignados previamente a un número finito, digamos 1024 o 2048, por razones de rendimiento. Utilizo un grupo de nodos que acelera la asignación de nodos y también me permite almacenar índices en lugar de punteros en mis estructuras de datos que son u16s (o u8 si tengo un máximo de 255 nodos, lo que hago en algunos juegos). Para mi pathfinding utilizo una cola de prioridad para la lista abierta, almacenando punteros a objetos Node. Se implementa como un montón binario, y clasifico los valores de coma flotante como enteros, ya que siempre son positivos y mi plataforma tiene comparaciones lentas de coma flotante. Utilizo una tabla hash para mi mapa cerrado para realizar un seguimiento de los nodos que he visitado. Almacena NodeIDs, no Nodes, para guardar en tamaños de caché.
Caché lo que puedas
Cuando visite un nodo por primera vez y calcule la distancia al destino, guarde en caché el nodo almacenado en el objeto de estado. Si vuelve a visitar el nodo, use el resultado en caché en lugar de calcularlo nuevamente. En mi caso, ayuda no tener que hacer una raíz cuadrada en los nodos revisitados. Puede encontrar que hay otros valores que puede calcular previamente y almacenar en caché.
Otras áreas que podría investigar: utilice la búsqueda de ruta bidireccional para buscar desde cualquier extremo. No he hecho esto, pero como otros han señalado, esto podría ayudar, pero no sin sus advertencias. La otra cosa en mi lista para probar es la búsqueda de rutas jerárquicas o la búsqueda de rutas en clúster. Hay una descripción interesante en la documentación de HavokAI Aquí que describe su concepto de agrupación, que es diferente de las implementaciones de HPA * descritas aquí .
Buena suerte y cuéntanos qué encuentras.