Je déconne avec l'écriture d'un RPG tactique vraiment pauvre en C ++. Jusqu'à présent, j'ai une carte de tuiles 2D et je viens de faire fonctionner l'algorithme A * basé sur le pseudocode dans le wikipedia .
Mais les vrais RPG tactiques ne se contentent pas de trouver le meilleur chemin sur un plan plat et de s'y déplacer. Ils ont généralement des gammes de mouvement limitées et doivent monter ou descendre. Si vous avez déjà joué à Final Fantasy Tactics, ceux-ci seront affectés par les statistiques de déplacement et de saut. C'est là que je me perds. Comment puis-je modifier l'algorithme A * afin qu'il trouve le meilleur chemin vers une cible, mais que le chemin ne soit long que de nombreuses tuiles? Comment dois-je prendre en compte les différences de hauteur et les statistiques de saut? Comment mettre en œuvre le saut par-dessus un écart?
Si cela peut aider, ma carte est actuellement représentée par un vecteur d'objets Tile. Chaque tuile a des pointeurs vers la tuile Nord, Sud, Est et Ouest, qui sont définis sur un nullptr s'il n'y a pas de tuile là-bas, comme le long du bord de la carte ou si une tuile est définie sur non-passable.
la source
Réponses:
L'escalade et les écarts ne sont que des fonctions de coût différentes. Pour une unité qui peut sauter l'écart a un coût normal (?), Tandis que pour une unité non sauteuse, elle a un coût arbitrairement élevé. L'escalade coûte plus cher, tout comme les terrains difficiles, etc. L'algorithme A * est bien capable de gérer les fonctions de coût, donc si votre implémentation ne le fait pas déjà, il suffit de google pour savoir comment implémenter A * avec une fonction de coût.
Cela dit, je ne pense pas que A * soit une approche particulièrement bonne pour un RPG tactique. Ou plus précisément, ce n'est pas une histoire complète. Vous ne voulez pas que vos unités beuglent aveuglément vers leur objectif, vous voulez qu'elles se positionnent pour exploiter la couverture, les hauteurs, peu importe, tout en progressant vers le but ultime et en cherchant à flanquer les adversaires et ainsi de suite. Ainsi, la valeur tactique du point final de chaque mouvement est d'une importance capitale, pas seulement la proximité de l'objectif. Cela nécessite une résolution des problèmes plus approfondie que la simple recherche de chemin.
la source
Lorsque vous voulez toutes les options de mouvement possibles d'une unité, utilisez l'algorithme de Dijkstra .
La différence entre A * et Dijkstra est que Dijkstra vous donne tous les itinéraires les plus courts possibles réalisables avec un coût donné, et si aucun d'entre eux n'atteint encore votre destination, il augmente le coût d'un et continue. A *, en revanche, préfère calculer d'abord les itinéraires qui ont de bonnes chances d'atteindre la destination.
Donc, lorsque vous voulez simplement le chemin le plus court du point A au point B, A * est un bon choix. Mais si vous voulez toutes les options de mouvement possibles et le chemin le plus court vers chacune d'elles, alors Dijkstra est exactement ce que vous voulez.
Tout ce que vous devez faire est d'exécuter l'algorithme de Dijksta sans nœud de destination spécifique, mais avec un coût maximum qui ne doit pas être dépassé (la plage de mouvement de l'unité). Lorsque le déplacement vers un nœud dépasse le coût maximum, ne le visitez pas. Lorsque l'algorithme se termine en raison du manque de bords non visités, chaque nœud de l'ensemble visité est une destination possible, et les marqueurs de nœud précédents des nœuds forment une liste liée représentant le chemin de retour au nœud initial.
En ce qui concerne les sauts: ceux-ci peuvent être représentés comme un autre avantage à la fois dans A * et Dijkstra. Ils peuvent avoir le même coût que la traversée d'un bord régulier ou différent. Vous pouvez également passer un paramètre "jump_height" à l'algorithme qui lui dit d'ignorer les sauts qui dépassent une hauteur donnée.
la source
A*
n'est vraiment qu'une généralisation de Dijkstra, donc si vous en comprenez un, il ne devrait pas être trop difficile de comprendre l'autre.Les autres réponses contiennent de bonnes informations, alors assurez-vous de les lire.
Cependant, pour répondre à votre question: en fonction du pseudocode auquel vous avez lié, vous avez une sorte de fonction
heuristic_cost_estimate
où vous calculez le coût de tileA à tileB (en supposant qu'ils sont adjacents). Au lieu d'utiliser un flat (1) pour ce coût, vous devrez l'ajuster pour inclure les statistiques des tuiles et des unités, et éventuellement des statistiques de bord.Par exemple:
Cela vous donnera votre chemin. Ensuite, vous déplaceriez simplement l'unité le long de son chemin tout en consommant des points de mouvement et les arrêteriez lorsque les points restants <edgeCost. Notez que cela peut ne pas être complètement optimal si vous vous retrouvez avec des points restants = 1, mais cela devrait être assez bon pour un RPG d'entraînement. En réalité, vous voudriez plus tactique, comme l'a souligné Jack Aidley!
Défi:
Si vous voulez devenir plus avancé, vous voulez probablement utiliser Djikstras comme suggéré pour trouver tous les espaces à une distance X, alors vous voulez évaluer chaque espace de cette liste pour un "meilleur" endroit, basé sur la proximité de la cible, la défense pouvoir, que vous puissiez ou non être attaqué à partir de cette position, etc. Sur la base de ces informations, vous choisiriez une tuile, puis vous y déplacer en suivant le chemin que vous venez de calculer en utilisant Djikstras.
la source
L'escalade et les lacunes sont assez triviales car elles ne modifient que le coût. La recherche de chemin (et la plupart de l'IA tactique) consiste à résumer le coût sur tous les nœuds à visiter et à le minimiser. Une falaise infranchissable aura un coût infini (très, très élevé), les pentes auront un coût plus élevé que la normale, etc.
Ceci, cependant, trouve le chemin globalement optimal qui n'est pas la meilleure solution car les vrais adversaires ne trouvent généralement pas le chemin optimal. C'est très irréaliste, parfois à un point qui est évident pour le joueur, et ennuyeux (surtout lorsque l'IA en tant que telle est fondamentalement invincible car elle aussi choisit l'optimum).
Les bonnes simulations ne trouvent délibérément pas le meilleur chemin. Un meilleur algorithme pourrait être de faire une recherche de chemin hiérarchique - si rien d'autre, en traçant une ligne droite sur la carte, et en prenant 4-5 points de cheminement, puis la recherche de chemin d'un point de cheminement au suivant, en ne considérant que les poids des nœuds qui sont jusqu'à présent connus et en définissant tous les autres poids de noeud sur "indifférents". Alternativement, vous pouvez d'abord exécuter A * sur une grille plus grossière, puis rechercher un chemin d'un grand nœud au suivant (mais je suppose que tracer une ligne sur la carte est très bien aussi).
Ceci est beaucoup plus réaliste (et consomme également une fraction de la puissance de traitement car le graphique est beaucoup plus petit). Oui, cela peut signifier qu'une unité se déplace vers une falaise uniquement pour découvrir qu'elle ne peut pas traverser. Ça va, ça arrive aussi à de vrais adversaires. La prochaine fois, cela ne se reproduira plus (car maintenant le coût infini est connu).
la source