Je travaille à essayer d'améliorer le repérage des ennemis de mon jeu. À l'heure actuelle, ils se déplacent essentiellement vers la position exacte du joueur en calculant l'angle entre eux et les joueurs et en se déplaçant dans cette direction. J'ai également un algorithme de flocage qui empêche les ennemis de s'empiler les uns sur les autres, ils se formeront donc en groupes plutôt que de se couper les uns les autres.
Cependant, maintenant que j'ai ajouté une carte à base de tuiles, j'ai besoin que les ennemis puissent également contourner les obstacles et les murs par exemple. J'ai d'abord essayé d'ajouter une valeur de séparation aux tuiles "non accessibles à pied" afin que l'algorithme de flocage considère les murs et les obstacles comme des objets à éloigner. Je dois encore déterminer si cela est faisable ou non, car mon test initial a montré que les ennemis frappaient un "mur" invisible où il n'y avait pas de tuiles non accessibles à pied, mais pour une raison quelconque, ils le frappaient et commençaient à briller.
Je me demandais si les performances pouvaient être trop lourdes pour calculer un chemin vers le joueur en utilisant A *, puis utiliser l'algorithme de flocage pour éviter l'agglutination. À l'origine, mon jeu allait être un jeu de tir basé sur les vagues, mais j'ai plutôt décidé de le faire en fonction du niveau dans la veine de Hotline Miami, il est donc probable que j'aurai moins d'ennemis, avec la horde occasionnelle, et je ferai juste les plus forts.
Est-ce une solution viable? J'utilise Java avec Slick2D comme moteur de jeu. Ou existe-t-il une meilleure solution / algorithme qui s'attaque à ces deux problèmes?
la source
Réponses:
Cela ressemble à un cas d'utilisation pour les champs de flux.
Dans cette technique, vous effectuez une seule requête de recherche de chemin vers l'extérieur à partir de vos objets joueur, en marquant chaque cellule que vous rencontrez avec la cellule à partir de laquelle vous l'avez atteinte.
Si toutes vos tuiles / arêtes ont un coût de traversée égal, vous pouvez utiliser une simple recherche en largeur pour cela. Sinon, l'algorithme de Dijkstra (comme A * sans objectif / heuristique) fonctionne.
Cela crée un champ de flux: une table de recherche qui associe chaque cellule à l'étape suivante vers l'objet joueur le plus proche de cette position.
Désormais, vos ennemis peuvent chacun rechercher leur position actuelle dans le champ de flux pour trouver la prochaine étape dans leur chemin le plus court évitant les obstacles vers l'objet joueur le plus proche, sans chacun faire leur propre requête de recherche de chemin.
Cela évolue de mieux en mieux avec le nombre d'ennemis que vous avez dans votre troupeau. Pour un seul ennemi, c'est plus cher que A * car il recherche sur toute la carte (bien que vous puissiez effectuer une sortie anticipée une fois que vous avez atteint tous les agents d'orientation). Mais au fur et à mesure que vous ajoutez des ennemis, ils partagent de plus en plus le coût de la recherche de chemin en calculant les segments de chemin partagés une fois plutôt que plusieurs fois. Vous bénéficiez également d'un avantage du fait que les BFS / Dijkdtra sont plus simples que A *, et généralement moins chers à évaluer par cellule inspectée.
Exactement là où le seuil de rentabilité frappe, de l'individu A * étant moins cher, à A * avec la mémorisation étant moins cher (où vous réutilisez certains des résultats d'une ancienne requête de recherche de chemin pour accélérer la suivante), pour que les champs de flux soient moins cher, dépendra de votre implémentation, du nombre d'agents et de la taille de votre carte. Mais si jamais vous prévoyez un grand essaim d'ennemis approchant de plusieurs directions dans une zone confinée, un champ d'écoulement sera presque certainement moins cher que A * itéré.
À titre d'exemple extrême, vous pouvez voir une vidéo ici avec 20 000 agents, tous simultanément à la recherche de chemins sur une grille relativement petite .
la source
Un * n'est pas très performant. J'aborderais cette situation en faisant varier les algorithmes. Faites A * de temps en temps et entre les deux, vérifiez si la prochaine étape est libre de monter ou si vous avez besoin d'évasion.
Par exemple, suivez la distance des joueurs par rapport à l'emplacement cible A *, si elle est supérieure à un seuil, recalculez un * puis effectuez simplement des mouvements de mise à jour. La plupart des jeux utilisent une combinaison de points de cheminement, par exemple une grille simplifiée pour la recherche de chemin et une logique qui gère le mouvement entre les points de cheminement avec des algorithmes de pilotage d'évasion utilisant des raycasts. Les agents tentent de courir vers un waypoint éloigné en manoeuvrant autour des obstacles à leur proximité est la meilleure approche à mon avis.
Il est préférable de travailler avec des machines à états finis ici et de lire le livre "Programming Game AI By Example" de Mat Buckland. Le livre propose des techniques éprouvées pour votre problème et détaille les mathématiques requises. Le code source du livre est disponible sur le Web; le livre est en C ++ mais certaines traductions (y compris Java) sont disponibles.
la source
Non seulement c'est faisable, je crois que cela a été fait dans un jeu commercial dans les années 90 - BattleZone (1998).
Ce jeu avait des unités 3D avec un mouvement gratuit sans tuiles et une construction de base à base de tuiles.
Voici comment cela semblait fonctionner:
Tout d'abord, A * ou quelque chose de similaire (probablement une variation de A * avec des limites strictes sur la durée d'un chemin, il ne prend donc jamais trop de ressources à exécuter mais ne trouve pas toujours un chemin jusqu'à la destination) serait utilisé pour trouver un chemin pour un hovertank pour arriver à sa destination sans se coincer dans des obstacles à base de tuiles.
Ensuite, le char volerait autour de l'espace jusqu'à ce qu'il soit attiré vers le centre d'une tuile voisine sur son chemin, et repoussé par des obstacles, d'autres chars à proximité, etc.
la source