Estoy jugando con escribir un RPG táctico realmente pobre en C ++. Hasta ahora tengo un mapa de mosaico 2D y acabo de hacer funcionar el algoritmo A * basado en el pseudocódigo de la wikipedia .
Pero los juegos de rol tácticos reales no solo encuentran el mejor camino en un avión plano y se mueven allí. Normalmente tienen rangos de movimiento limitados y deben subir o bajar. Si alguna vez jugaste a Final Fantasy Tactics, estas se verían afectadas por las estadísticas Move and Jump. Aquí es donde me pierdo. ¿Cómo modifico el algoritmo A * para que encuentre la mejor ruta hacia un objetivo, pero la ruta solo tiene unas pocas fichas? ¿Cómo debo tener en cuenta las diferencias de altura y las estadísticas de salto? ¿Cómo implemento saltar sobre una brecha?
Si ayuda, en este momento mi mapa está representado por un Vector de objetos de mosaico. Cada mosaico tiene punteros a los mosaicos Norte, Sur, Este y Oeste, que se configuran en nullptr si no existe ningún mosaico allí, como a lo largo del borde del mapa o si un mosaico se configura como no transitable.
fuente
Respuestas:
La escalada y las brechas son funciones de costo diferentes. Para una unidad que puede saltar la brecha tiene un costo normal (?), Mientras que para una unidad que no salta tiene un costo arbitrariamente alto. Los costos de escalada adicionales, al igual que el terreno difícil, etc. El algoritmo A * es capaz de manejar funciones de costos, por lo que si su implementación aún no lo está haciendo, solo busque en Google cómo implementar A * con una función de costos.
Dicho esto, sin embargo, no creo que A * sea un enfoque particularmente bueno para un juego de rol táctico. O más exactamente, no es una historia completa. No quieres que tus unidades se equivoquen ciegamente hacia su objetivo, quieres que se posicionen para explotar la cobertura, el terreno elevado, lo que sea, mientras avanzan hacia el objetivo final y buscan flanquear a los oponentes, etc. Por lo tanto, el valor táctico del punto final de cada movimiento es de gran importancia, no solo qué tan cerca está el objetivo. Esto requiere una resolución de problemas más profunda que la simple búsqueda de caminos.
fuente
Cuando desee todas las opciones de movimiento posibles de una unidad, use el Algoritmo de Dijkstra .
La diferencia entre A * y Dijkstra es que Dijkstra le ofrece todas las rutas más cortas posibles que se pueden lograr con un costo dado, y si ninguna de ellas llega a su destino todavía, aumenta el costo en una y continúa. A *, por otro lado, prefiere calcular primero aquellas rutas que tienen una buena oportunidad de llegar al destino.
Entonces, cuando solo desea la ruta más corta desde el punto A al punto B, entonces A * es una buena opción. Pero si desea todas las opciones de movimiento posibles y el camino más corto para cada una de ellas, entonces Dijkstra es exactamente lo que desea.
Todo lo que necesita hacer es ejecutar el algoritmo de Dijksta sin un nodo de destino específico, pero con un costo máximo que no debe superarse (el rango de movimiento de la unidad). Cuando viajar a un nodo excedería el costo máximo, no lo visite. Cuando el algoritmo termina debido a la falta de bordes no visitados, cada nodo en el conjunto visitado es un posible destino, y los marcadores de nodo anteriores de los nodos forman una lista vinculada que representa la ruta de regreso al nodo inicial.
Con respecto a los saltos: pueden representarse como otra ventaja en A * y Dijkstra. Pueden tener el mismo costo que atravesar un borde regular o uno diferente. También puede pasar un parámetro "jump_height" al algoritmo que le dice al algoritmo que ignore los bordes de salto que exceden una altura dada.
fuente
A*
realidad es solo una generalización de Dijkstra, por lo que si comprende uno, no debería ser demasiado difícil de entender el otro.Las otras respuestas tienen buena información, así que asegúrese de leerlas.
Sin embargo, para responder a su pregunta: según el pseudocódigo al que se vinculó, tiene algún tipo de función
heuristic_cost_estimate
en la que calcula el costo de tileA a tileB (suponiendo que sean adyacentes). En lugar de usar un plano (1) para ese costo, tendrías que ajustarlo para incluir las estadísticas de mosaico y estadísticas de unidad, y posiblemente estadísticas de borde.Por ejemplo:
Esto te dará tu camino. Luego, simplemente movería la unidad a lo largo de su camino mientras consumía puntos de movimiento y los detendría cuando quedara Puntos <edgeCost. Tenga en cuenta que esto puede no ser completamente óptimo si termina con puntos restantes = 1, pero debería ser lo suficientemente bueno para un RPG de práctica. ¡En realidad, querrías más táctica, como señaló Jack Aidley!
Desafío:
si desea avanzar más, probablemente desee usar Djikstras como se sugiere para encontrar todos los espacios dentro de la distancia X, entonces desea evaluar cada espacio en esa lista para un "mejor" lugar, basado en la cercanía al objetivo, defensa poder, si puedes ser atacado o no desde esa posición, etc. Según esa información, elegirías un mosaico y luego te moverías allí siguiendo el camino que acabas de calcular usando Djikstras.
fuente
La escalada y las brechas son bastante triviales ya que solo modifican el costo. Pathfinding (y la mayoría de la IA táctica) se trata de resumir el costo en todos los nodos que se visitarán y minimizar eso. Un acantilado intransitable tendrá un costo infinito (muy, muy alto), las pendientes tendrán un costo más alto de lo normal, etc.
Esto, sin embargo, encuentra el camino óptimo a nivel mundial que no es la mejor solución porque los adversarios reales generalmente no encuentran el camino óptimo. Es muy poco realista, a veces hasta un punto que es obvio para el jugador, y molesto (especialmente cuando la IA como tal es básicamente invencible porque también elige lo óptimo).
Las buenas simulaciones deliberadamente no encuentran el mejor camino. Un algoritmo mucho mejor podría ser encontrar rutas jerárquicas: si no, dibujando una línea recta en el mapa y tomando de 4 a 5 puntos de ruta, busque rutas de un punto de ruta al siguiente, considerando solo los pesos de nodos que están tan lejos conocido, y establecer todos los demás pesos de nodo a "indiferente". Alternativamente, puede ejecutar A * en una cuadrícula más gruesa primero, y luego buscar ruta desde un nodo grande al siguiente (pero supongo que dibujar una línea en el mapa también está bien).
Esto es mucho más realista (y también consume una fracción de la potencia de procesamiento porque el gráfico es mucho más pequeño). Sí, puede significar que una unidad se mueve hacia un acantilado solo para descubrir que no puede cruzar. Eso está bien, también les sucede a los verdaderos adversarios. La próxima vez, no volverá a suceder (porque ahora se conoce el costo infinito).
fuente