Comment implémenter un ennemi intelligent dans un shoot-em-up?


13

Imaginez un shoot-em-up très simple, quelque chose que nous savons tous:

shoot-em-up 1

Vous êtes le joueur (vert). Votre mouvement est limité à l' Xaxe. Notre ennemi (ou ennemis) est en haut de l'écran, son mouvement est également limité à l' Xaxe. Le joueur tire des balles (jaunes) sur l'ennemi.

J'aimerais implémenter une IA pour l'ennemi qui devrait être vraiment bonne pour éviter les balles des joueurs. Ma première idée a été de diviser l'écran en sections discrètes et de leur attribuer des poids:

shoot-em-up pondéré

Il y a deux poids: Le "poids de balle" (gris) est le danger imposé par une balle. Plus la balle est proche de l'ennemi, plus le "poids de la balle" ( 0..1, où 1 est le plus grand danger). Les voies sans balle ont un poids de 0. Le deuxième poids est le "poids à distance" (vert lime). Pour chaque voie, j'ajoute le 0.2coût de déplacement (cette valeur est maintenant un peu arbitraire et pourrait être modifiée).

Ensuite, j'ajoute simplement les poids (blancs) et je vais dans la voie avec le poids le plus bas (rouge). Mais cette approche a un défaut évident, car elle peut facilement manquer des minima locaux car l'endroit optimal où aller serait simplement entre deux balles entrantes (comme indiqué par la flèche blanche).

Voici donc ce que je recherche:

destruction totale shoot-em-up

  • Devrait trouver un moyen de traverser la tempête de balles, même quand il n'y a aucun endroit qui n'impose une menace de balle.
  • L'ennemi peut esquiver les balles de manière fiable en choisissant une solution optimale (ou presque optimale).
  • L'algorithme doit être en mesure de prendre en compte la vitesse de déplacement des balles (car elles peuvent se déplacer avec des vitesses différentes).
  • Façons de modifier l'algorithme afin que différents niveaux de difficulté puissent être appliqués (idiot aux ennemis super-intelligents).
  • L'algorithme devrait permettre des objectifs différents, car l'ennemi ne veut pas seulement échapper aux balles, il doit également pouvoir tirer sur le joueur. Cela signifie que les positions où l'ennemi peut tirer sur le joueur devraient être préférées lors de l'esquive des balles.

Alors, comment aborderiez-vous cela? Contrairement à d'autres jeux de ce genre, j'aimerais avoir seulement quelques ennemis, mais très "qualifiés" au lieu de masses d'ennemis stupides.


2
Avez-vous envisagé d'utiliser quelque chose comme des comportements de pilotage? Il y en a un pour l'évitement d'obstacles spécifiquement: red3d.com/cwr/steer/Obstacle.html
Tetrad

@Tetrad J'ai pensé aux comportements de pilotage .. aussi parce qu'ils peuvent très bien être commutés, comme "essayer de tirer sur le joueur" et quand le danger est devant, passer à "esquiver". Je crains qu'une version 1D (c'est ce que je traite essentiellement) d'évasion soit trop stupide pour prendre de bonnes décisions. Je peux me tromper cependant.
bummzack

Réponses:


8

Je pense que votre idée de base est saine, mais ce n'est pas analogique. Vous avez besoin d'un champ de valeur analogique qui traverse l'écran. Donc, gradient de diffusion 1D, à partir duquel vous pouvez dériver une valeur à un point exact sur cette ligne, à la volée. Les gradients de diffusion sont bon marché et peuvent être utilisés par plusieurs ennemis à la fois, car ils décrivent l'environnement, et non la vue de l'entité (un peu comme l'éclairage de radiosité) - probablement pourquoi vous avez opté pour l'approche que vous avez dans votre question . Ce gradient doit être relativement lisse, afin d'évoquer le mouvement organique de l'ennemi, et se met évidemment à jour comme le fait votre gamestate. Peut-être une moyenne mobile ?

Le gradient doit combiner:

  • Proximité
  • Rapidité
  • Étendue de balle
  • (facultatif) Position des cibles (joueurs)

Pour esquiver, il faut pouvoir trouver une solution avec précision chaque fois qu'une solution existe . Tel est le cas chaque fois qu'il y a un espace suffisamment petit pour que l'ennemi puisse l'esquiver. Autrement dit, vous ne pouvez faire que ce que vous pouvez faire, donc l'approche par gradient ne fonctionnera pas pire que toute autre approche dans ce sens, je dirais.

Le gradient de diffusion devrait pousser l'ennemi vers des optima locaux (étant les pics du graphique) avec moins d'impératifs de déplacement, plus nous nous rapprochons d'un minimum local, d'où un effet de rendement décroissant sur l'esquive. Cela ouvre la porte à une prise de décision plus intelligente quant au moment où l'ennemi a une bonne ouverture au feu.

Si le besoin de tirer est plus grand que le besoin de bouger, faites-le; votre code peut également déterminer cela en fonction de leur différence. Vous pouvez l'implémenter dans le cadre du graphique de base, auquel cas la position du joueur réduit les valeurs environnantes dans le graphique (en supposant que les ennemis gravitent au point le plus bas), qui combine toutes les décisions dans un graphique, ou vous pouvez conserver le " graphique "désir de tirer" distinct du graphique principal "désir d'esquiver", qui vous offrira un contrôle plus direct.

IRL, je ne prendrais pas la peine d'esquiver un projectile jusqu'à ce qu'il soit à une distance que je sais, à ma vitesse d'esquive maximale, commence à devenir difficile à éviter. Expérience de première main en lançant des pierres comme un garçon. Une balle à une distance x se déplaçant à la vitesse y a le même indice de danger qu'une balle à une distance 2x se déplaçant à 2 ans. Cela doit donc être pris en compte correctement.

Les moyens de modifier l'algorithme pour la difficulté de l'ennemi incluent

  • introduction d'une latence sur les mises à jour du graphique (Born Too Slow)
  • introduire des inexactitudes aléatoires et localisées dans le graphique
  • simplement que les ennemis n'obéissent pas à ce que le graphique leur dit, sur une séquence de mises à jour (disons 1 à 10 images) en raison de la pure paresse de l'IA.

Encore une fois, vous pouvez soit implémenter tous les facteurs dans un graphique (moins de contrôle et moins utile pour plusieurs ennemis), soit dans plusieurs graphiques que vous regardez ensemble pour obtenir les résultats (plus modulaires, fonctionnent probablement mieux pour plusieurs ennemis). Il est difficile d'être plus précis, car il existe de nombreuses directions dans lesquelles vous pouvez adopter cette approche.


1
Cher Nick. Je suis allé de l'avant et j'ai implémenté une petite version test de ce comportement en flash et je suis très satisfait du résultat (les balles sont générées au hasard). J'utilise actuellement 3 dégradés, un pour la menace, le coût du mouvement et un statique pour les bords (de sorte que les bords de l'écran sont moins souhaitables). Ils sont visualisés dans l'application flash. Je pense qu'avec quelques ajustements, je peux obtenir de très bons résultats et prendre en compte d'autres poids comme les positions de prise de vue. Merci beaucoup mon pote.
bummzack

1
Hé @bummzack, c'est un compagnon de plaisir, c'est une petite démo sympa! Votre point de vue sur le problème était nouveau pour moi et semblait intéressant - je suis heureux de voir que cela fonctionne! Heureux de vous aider et merci pour le partage.
Ingénieur

7

Cela peut être considéré comme un problème de cheminement. Au lieu de penser à la façon dont le méchant évite les balles, l'imagerie des balles est statique et le méchant doit les traverser jusqu'au bas de l'écran.

    E    
B  B**B
  B***B  B
 B***B   B
B**B** B 
 B**B**BB
B*****B B
      P

E = ennemi
B = balle
P = joueur
* = options de chemin vers le bas de l'écran

Une fois que le méchant a tracé un chemin réussi, il lui suffit de passer à l'étape suivante à chaque fois. Il existe probablement déjà de bons algorithmes pour trouver un chemin comme celui-ci. Si le méchant se déplace à la même vitesse que les balles, un exemple d'algorithme pourrait être;

Commencez par le baddy et marquez les positions de sécurité dans les espaces vides en bas à gauche, directement en dessous et en bas à droite. Considérez ensuite chaque espace sûr que vous venez de créer et répétez. Si à tout moment vous trouvez qu'il n'y a pas d'espaces sûrs ci-dessous, marquez l'espace comme non sûr et revenez en arrière.


1
Approche intéressante. Je crains que cela soit un peu cher, car l'environnement change si vite et il est difficile d'utiliser des algorithmes de recherche de chemin communs car ils fonctionnent mieux avec des "cartes" discrètes.
bummzack

Cela ne devrait pas être trop cher, n'oubliez pas que vous n'avez qu'à calculer la ligne du bas à chaque tour, vous n'avez pas à recalculer le tout.
Qwerky

@bummzack Environment n'est pas "rapide", du moins, en termes d'ordinateur. Pour les développeurs de jeux, vous devez comprendre que presque tous les jeux sont basés sur des étapes, c'est à peu près la taille de cette étape. Mais, à chaque étape, des calculs peuvent être effectués, donc la solution Qwerky est la chose dont vous avez besoin.
Deele

En fait, je suis d'accord avec @bummzack. Bien que cette approche soit logiquement solide, elle coûtera plus cher que l'approche 1D proposée dans la question. Peut-être une optimisation prématurée, mais je trouve cette approche beaucoup plus élégante. Voir ma réponse pour une élaboration à ce sujet.
Ingénieur

2
C'est probablement la bonne réponse, mais pas exactement une réponse réaliste . Dans le temps qu'il faut à l'ennemi pour trouver un chemin, le champ peut avoir un autre jeu de balles qui invalide complètement le chemin, ce qui signifie que recalculer le chemin serait un must. Et le recalcul est un chienne . De plus, votre idée de rétropropagation à un point où il était sûr le rend encore plus cher! @Nick Wiggill Je ne pense pas que ce soit une optimisation prématurée, juste une bonne prévoyance pour vous assurer de ne pas vous botter à l'entrejambe.
Ray Dey
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.