Créer un jeu de hockey IA à l'aide de comportements de direction défense

Ce tutoriel est la dernière étape du processus de codage d’une partie de hockey à l’aide de comportements de conduite et de machines à états finis. Ici, nous améliorerons l'intelligence artificielle de nos athlètes pour leur permettre de défendre leur but contre leurs adversaires. Nous ferons également en sorte que nos athlètes exécutent certaines tactiques d'attaque pendant qu'ils se défendent, afin qu'ils puissent récupérer le puck et mettre fin à l'offensive de l'adversaire..

Quelques mots sur la défense

Dans un match de compétition comme le hockey, le processus de défense est beaucoup plus que de se précipiter dans la zone de but de l'équipe pour empêcher l'adversaire de marquer. Empêcher l'adversaire de marquer n'est qu'une des nombreuses tâches à accomplir.

Si une équipe se concentre uniquement sur des tactiques de prévention des points, tous les athlètes deviendront simplement des obstacles en cours de route. L'adversaire continuera à pousser, en essayant de trouver une place dans la formation de défense. Cela prendra du temps, mais l’adversaire finira par marquer.

Le processus de défense est un mélange d'actions défensives et offensives. Le meilleur moyen de mettre fin à l'attaque de l'adversaire, qui est l'objectif de la défense, est de: attaquer en défendant. Cela peut sembler un peu déroutant, mais c'est parfaitement logique.

Un athlète défendant son équipe doit avancer vers son but, empêchant ainsi l'adversaire de marquer. En cours de route, il doit essayer de voler le puck à l'adversaire qui le porte ou d'intercepter le puck lorsqu'il est échangé entre les adversaires. C’est exactement ce que ce tutoriel va essayer de mettre en oeuvre: une tactique défensive avec des actions d’attaque.

Combinant Attaque et Défense

Afin d'obtenir un comportement défensif comportant certains aspects d'attaque, nous allons ajouter deux nouveaux états à la machine à états finis de l'IA:

Une machine à états finis basée sur des piles représentant l'attaque et les processus de défense…

le défendre l'état sera la pierre angulaire du processus de défense. Dans cet état, les athlètes se déplaceront du côté de la patinoire en essayant toujours de récupérer la rondelle pour mettre fin à l'offensive de l'adversaire.. 

le patrouille Etat complétera le processus de défense. Cela empêchera les athlètes de rester immobiles lorsqu'ils atteindront leur position de défense sur la patinoire. Cet état maintiendra les athlètes en mouvement et en patrouille dans la zone, ce qui produira un résultat plus convaincant..

Comprendre l'état de défense

le défendre l'état est basé sur une idée très simple. Lorsqu'il est actif, chaque athlète se rapprochera de sa position initiale dans la patinoire. Nous avons déjà utilisé cette position, décrite par le mInitialPosition propriété dans le Athlète classe, pour mettre en œuvre le prepareForMatch Etat dans le premier tutoriel de cette série.

En se rapprochant de sa position initiale, un athlète tentera d’attaquer son adversaire s’il est suffisamment proche et porte la rondelle. Par exemple, si l’athlète est en mouvement et que le chef de l’adversaire (celui qui a la rondelle) devient voisin, le défendre l’Etat sera remplacé par quelque chose de plus approprié, comme le StealPuck Etat.

Étant donné que les athlètes ont tendance à se propager à travers la patinoire lors de l’attaque, défendre et commencent à revenir à leur position initiale, ils couvriront une zone importante, assurant un schéma de défense convaincant:

Athlètes effectuant des actions d'attaque tout en reprenant leurs positions de défense initiales.

Certains athlètes ne rencontreront pas d’opposants en cours de route. Ils se contenteront donc de se rapprocher de leur position initiale. D'autres athlètes, cependant, pourraient se rapprocher de certains adversaires intéressants, tels que le meneur (celui qui porte la rondelle).

Mettre en place l'état de défense

le défendre l'état aura quatre transitions:

L'état de la défense et ses transitions dans le FSM décrivant le processus de défense…

Trois d'entre eux, l'équipe a la rondelle, proche du leader adverse, et la rondelle n'a pas de propriétaire, sont liés à des actions d'attaque. Ils seront responsables de donner l’impression que les athlètes s’attaquent à leurs adversaires tout en se déplaçant pour défendre le but de l’équipe. le en position la transition sera déclenchée lorsque l'athlète arrivera enfin à sa position initiale dans la patinoire.

La première étape dans la mise en œuvre de la défendre l'état consiste à faire avancer l'athlète vers sa position initiale. Puisqu'il doit ralentir au fur et à mesure qu'il se rapproche de la destination, le comportement de la direction lors de l'arrivée se fait parfaitement:

class Athlete // (…), fonction privée Defend (): void var aPuckOwner: Athlete = getPuckOwner (); // Déplacez-vous vers la position initiale pour y arriver en douceur. mBoid.steering = mBoid.steering + mBoid.arrive (mInitialPosition); // La rondelle a-t-elle un propriétaire? if (aPuckOwner! = null) // Oui, c'est le cas. Qui l'a? if (doesMyTeamHasThePuck ()) // Mon équipe a la rondelle, il est temps d'arrêter de défendre et de commencer à attaquer! mBrain.popState (); mBrain.pushState (attaque);  else if (Utils.distance (aPuckOwner, this) < 150)  // An opponent has the puck and he is close to us! // Let's try to steal the puck from him. mBrain.popState(); mBrain.pushState(stealPuck);   else  // No, the puck has no owner, it is running in the rink. // There is no point to keep defending the goal, because nobody has the puck. // Let's switch to 'pursuePuck' and try to get the puck to our team. mBrain.popState(); mBrain.pushState(pursuePuck);   // (… ) 

Le comportement à l’arrivée créera une force qui poussera l’athlète vers sa position initiale (mInitialPosition) tandis que le défendre l'état est actif. Après le calcul de la force d’arrivée, dans ce code, nous exécutons une séquence de tests qui vérifieront la propriété du puck et la proximité des adversaires, en faisant apparaître le résultat final. défendre état du cerveau et en poussant un nouveau en fonction de la situation.

Si la rondelle n'a pas de propriétaire, elle se déplace probablement librement dans la patinoire. Dans ce cas, le poursuivrePuck l'état sera poussé dans le cerveau (ligne 29). Si la rondelle a un propriétaire d’équipe, cela signifie que le processus de défense est terminé et que le moment est venu d’attaquer (ligne 16). Enfin si le propriétaire de la rondelle appartient à l'équipe adverse et qu'il est suffisamment proche, StealPuck sera poussé dans le cerveau (ligne 22).

Le résultat est une équipe capable de défendre son objectif, poursuivant et essayant de voler la rondelle à l'adversaire qui la porte. Vous trouverez ci-dessous une démonstration de la mise en œuvre actuelle de defence

Patrouiller la zone

Le comportement actuel de la défense est acceptable, mais il peut être légèrement modifié pour être plus convaincant. Si vous analysez la démo précédente, vous remarquerez peut-être que les athlètes s’arrêteront après avoir atteint leur position initiale pendant la défense.. 

Si un athlète revient à sa position initiale sans rencontrer d’adversaire en cours de route, il reste immobile jusqu’à ce qu’un adversaire avec la rondelle passe ou que l’équipe récupère la rondelle.. 

Nous pouvons améliorer ce comportement en ajoutant un patrouille état, qui est poussé dans le cerveau par le défendre indiquer quand l'athlète aura atteint sa position initiale:

L'état de la patrouille et ses transitions dans le FSM décrivant le processus de défense.

le patrouille l'état est extrêmement simple. Une fois actif, les athlètes se déplaceront de manière aléatoire pendant une courte période, ce qui imitera visuellement le comportement attendu d'un athlète essayant de défendre une place sur la patinoire..

Lorsque la distance entre l'athlète et sa position initiale est supérieure à dix, par exemple, patrouille se dégage du cerveau et pousse défendre. Si l'athlète revient à sa position initiale tout en défendant, patrouille est poussé une fois de plus dans le cerveau et le processus se répète:

Démonstration de l'état de patrouille.

Le modèle de mouvement aléatoire requis par le patrouille l'état peut être facilement atteint avec le comportement de direction errant. La mise en œuvre de la patrouille l'état est:

classe Athlete // (…) fonction privée patrol (): void mBoid.steering = mBoid.steering + mBoid.wander (); // Est-ce que je suis trop loin de ma position initiale? if (Utils.distance (mInitialPosition, this)> 10) // Ouais, je le suis. Il est temps d'arrêter de patrouiller et de revenir à // ma position initiale. mBrain.popState (); mBrain.pushState (défendre);  // (…)

Le contrôle de distance (ligne 8) veille à ce que l'athlète patrouille une petite zone autour de sa position initiale au lieu de laisser sa position de défense initiale complètement sans surveillance.

Les résultats de l'utilisation du patrouille l'état est un comportement plus convaincant:

Mettre tous ensemble

Pendant la mise en œuvre de la StealPuck dans le didacticiel précédent, il y avait une situation où les athlètes devraient passer à la défendre Etat. Cependant, cet état n'a pas été mis en œuvre à l'époque.

En essayant de voler la rondelle (la StealPuck si l’adversaire est trop éloigné de l’athlète, il est inutile de continuer à essayer de voler la rondelle. La meilleure option dans cette situation est de faire apparaître le StealPuck état et pousser défendre, espérant qu'un coéquipier sera plus proche du chef de l'adversaire pour voler la rondelle.

le StealPuck l'état doit être changé (lignes 28 et 29) pour permettre aux athlètes de pousser le défendre dans cette situation:

Athlète de classe // (…) fonction privée stealPuck (): void // Le puck a-t-il un propriétaire? if (getPuckOwner ()! = null) // Oui, oui, mais qui l'a? if (doesMyTeamHasThePuck ()) // Mon équipe a le puck, il est donc temps d'arrêter d'essayer de voler // le puck et de commencer à attaquer. mBrain.popState (); mBrain.pushState (attaque);  else // Un adversaire a le puck. var aOpponentLeader: Athlete = getPuckOwner (); // L'adversaire avec la rondelle est-il proche de moi? si (Utils.distance (aOpponentLeader, this) < 150)  // Yeah, he is close! Let's pursue him while mantaining a certain // separation from the others to avoid that everybody will ocuppy the same // position in the pursuit. mBoid.steering = mBoid.steering + mBoid.pursuit(aOpponentLeader.boid); mBoid.steering = mBoid.steering + mBoid.separation(50);  else  // No, he is too far away. Let's switch to 'defend' and hope // someone closer to the puck can steal it for us. mBrain.popState(); mBrain.pushState(defend);    else  // The puck has no owner, it is probably running freely in the rink. // There is no point to keep trying to steal it, so let's finish the 'stealPuck' state // and switch to 'pursuePuck'. mBrain.popState(); mBrain.pushState(pursuePuck);   // (… ) 

Après avoir mis à jour le StealPuck les athlètes sont désormais en mesure d’organiser leurs tactiques d’attaque et de défense, ce qui permet à deux équipes contrôlées par l’IA de jouer l’une contre.

Le résultat est démontré ci-dessous:

Conclusion

Dans ce tutoriel, nous avons implémenté une tactique de défense utilisée par les athlètes pour défendre leur objectif contre leurs adversaires. Nous avons ensuite amélioré la défendre en ajoutant quelques actions d'attaque, telles que tenter de voler la rondelle de l'adversaire, ce qui rendait la tactique de défense plus naturelle et plus convaincante.

Nous avons également amélioré l’atmosphère du comportement de la défense en ajoutant un état extrêmement simple mais puissant, le patrouille. L'idée est d'empêcher les athlètes de rester immobiles tout en défendant le but de leur équipe.

Et avec cela, nous avons créé un système complet d'IA pour notre jeu de hockey! 

Références

  • Sprite: Stade de hockey sur GraphicRiver
  • Sprites: joueurs de hockey par Taylor J Glidden