Crear un juego de hockey AI utilizando comportamientos de dirección defensa

Este tutorial es la parte final en el proceso de codificación de un juego de hockey con comportamientos de dirección y máquinas de estados finitos. Aquí, mejoraremos la inteligencia artificial de nuestros atletas para permitirles defender su objetivo contra sus oponentes. También haremos que nuestros atletas realicen algunas tácticas de ataque mientras están defendiendo, para que puedan recuperar el puck y terminar la ofensiva del oponente..

Unas pocas palabras sobre la defensa

En un juego competitivo como el hockey, el proceso de defensa es mucho más que correr hacia el área de portería del equipo para evitar que el oponente anote. Evitar que el oponente anote es solo una de las muchas tareas involucradas.

Si un equipo se enfoca solo en tácticas de prevención de puntajes, todos los atletas se convertirán en simples obstáculos en el camino. El oponente seguirá empujando, tratando de encontrar un lugar en la formación de defensa. Tomará tiempo, pero eventualmente el oponente marcará.

El proceso de defensa es una mezcla de acciones defensivas y ofensivas. La mejor manera de terminar el ataque del oponente, que es el objetivo de la defensa, es atacar mientras se defiende. Puede sonar un poco confuso, pero tiene mucho sentido.

Un atleta que defiende a su equipo debe avanzar hacia su meta, evitando que el oponente anote. En el camino, debe intentar robar el disco del oponente que lo lleva, o interceptarlo cuando se intercambia entre los oponentes. Eso es exactamente lo que intentará implementar este tutorial: una táctica defensiva con acciones de ataque..

Combinando ataque y defensa

Para lograr un comportamiento defensivo que tenga algunos aspectos de ataque, agregaremos dos nuevos estados a la máquina de estado finito de AI:

Una máquina de estados finitos basada en la pila que representa el ataque y los procesos de defensa ...

los defender El estado será la piedra fundamental en el proceso de defensa. Mientras estén en ese estado, los atletas se moverán hacia su lado de la pista, siempre tratando de recuperar el disco para terminar con la ofensiva del oponente.. 

los patrulla El estado complementará el proceso de defensa. Evitará que los atletas se queden quietos cuando alcancen su posición de defensa en la pista. Este estado mantendrá a los atletas en movimiento y patrullando el área, lo que producirá un resultado más convincente.

Entendiendo el estado de defensa

los defender El estado se basa en una idea muy simple. Cuando está activo, cada atleta se moverá hacia su posición inicial en la pista. Ya utilizamos esta posición, descrita por el Posicion Inicial propiedad en el Atleta clase, para implementar el prepareForMatch Estado en el primer tutorial de esta serie..

Mientras se mueve hacia su posición inicial, un atleta intentará realizar algunas acciones de ataque contra el oponente si está lo suficientemente cerca y lleva el disco. Por ejemplo, si el atleta se está moviendo y el líder del oponente (el que tiene el puck) se convierte en un vecino, el defender Estado será reemplazado por algo más apropiado, como el robar estado.

Dado que los atletas tienden a extenderse por toda la pista mientras atacan, cuando cambian a defender y comenzar a regresar a su posición inicial, cubrirán un área significativa, asegurando un patrón de defensa convincente:

Atletas realizando acciones de ataque mientras regresan a sus posiciones iniciales de defensa..

Algunos atletas no se encontrarán con oponentes en el camino, por lo que simplemente se moverán hacia su posición inicial. Sin embargo, otros atletas podrían acercarse a algunos oponentes interesantes, como el líder (el que lleva el puck)..

Implementando el estado de defensa

los defender El estado tendrá cuatro transiciones:

El estado de defensa y sus transiciones en el FSM que describe el proceso de defensa ...

Tres de ellos, el equipo tiene el puck, cerca del líder oponente, y puck no tiene dueño, Están relacionados con las acciones de ataque. Serán responsables de hacer que los atletas se vean como si estuvieran atacando a sus oponentes mientras se mueven para defender la meta del equipo. los en posición la transición se activará cuando el atleta finalmente llegue a su posición inicial en la pista.

El primer paso para implementar el defender Estado es hacer que el atleta se mueva hacia su posición inicial. Dado que debe disminuir la velocidad a medida que se acerca al destino, el comportamiento de la dirección de llegada es el ajuste perfecto:

class Athlete // (...) private function defend (): void var aPuckOwner: Athlete = getPuckOwner (); // Muévete hacia la posición inicial, llegando allí sin problemas. mBoid.steering = mBoid.steering + mBoid.arrive (mInitialPosition); // ¿El puck tiene dueño? if (aPuckOwner! = null) // Sí, lo ha hecho. ¿Quien lo tiene? if (doesMyTeamHasThePuck ()) // ¡Mi equipo tiene el puck, es hora de dejar de defender y comenzar a atacar! mBrain.popState (); mBrain.pushState (ataque);  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);   // (… ) 

El comportamiento de llegada creará una fuerza que empujará al atleta hacia su posición inicial (Posicion Inicial) mientras que la defender El estado es activo. Después del cálculo de la fuerza de llegada, en este código, ejecutamos una secuencia de pruebas que verificará la propiedad del disco y la proximidad de los oponentes, haciendo estallar la defender Estado desde el cerebro y empujando uno nuevo de acuerdo a la situación..

Si el puck no tiene dueño, probablemente se mueva libremente en la pista. En ese caso, el continuePuck estado será empujado en el cerebro (línea 29). Si el puck tiene un propietario de equipo, significa que el proceso de defensa ha terminado y es hora de atacar (línea dieciséis). Finalmente, si el dueño del puck pertenece al equipo oponente y está lo suficientemente cerca., robar será empujado hacia el cerebro (línea 22).

El resultado es un equipo que es capaz de defender su objetivo, persiguiendo e intentando robar el disco del oponente que lo lleva. A continuación se muestra una demostración de la implementación actual de la defensa:

Patrullando la zona

El comportamiento de defensa actual es aceptable, pero puede modificarse un poco para ser más convincente. Si analiza la demostración anterior, puede notar que los atletas se detendrán y se detendrán una vez que alcancen su posición inicial mientras defienden.. 

Si un atleta regresa a su posición inicial sin encontrarse con ningún oponente en el camino, permanecerá quieto hasta que pase un oponente con el puck o el equipo recupere el puck.. 

Podemos mejorar este comportamiento añadiendo un patrulla Estado, que es empujado en el cerebro por el defender Estado cuando el atleta alcanza su posición inicial:

El estado de la patrulla y sus transiciones en el FSM que describen el proceso de defensa..

los patrulla El estado es extremadamente simple. Cuando está activo, hará que los atletas se muevan aleatoriamente por un corto tiempo, lo que imita visualmente el comportamiento esperado de un atleta que intenta defender un lugar en la pista..

Cuando la distancia entre el atleta y su posición inicial es mayor que 10, por ejemplo, patrulla salta del cerebro y empuja defender. Si el atleta llega a su posición inicial nuevamente mientras defiende, patrulla Se empuja una vez más en el cerebro y el proceso se repite:

Demostración del estado patrullero..

El patrón de movimiento aleatorio requerido por el patrulla El estado se puede lograr fácilmente con el comportamiento de la dirección errante. La implementación de la patrulla estado es:

class Athlete // (…) patrol de función privada (): void mBoid.steering = mBoid.steering + mBoid.wander (); // ¿Estoy demasiado lejos de mi posición inicial? if (Utils.distance (mInitialPosition, this)> 10) // Sí, lo soy. Es hora de dejar de patrullar y volver a // mi posición inicial. mBrain.popState (); mBrain.pushState (defender);  // (…)

El control de distancia (línea 8) se asegura de que el atleta patrulle un área pequeña alrededor de su posición inicial en lugar de dejar su posición de defensa inicial completamente desatendida.

Los resultados de usar el patrulla Estado es un comportamiento más convincente:

Poniendolo todo junto

Durante la implementación del robar En el tutorial anterior, había una situación en la que los atletas debían cambiar a la defender estado. Sin embargo, ese estado no fue implementado en aquel entonces..

Mientras intentaba robar el disco robar estado), si el oponente está demasiado lejos del atleta, no tiene sentido seguir intentando robar el puck. La mejor opción en esa situación es hacer estallar la robar estado y empuje defender, con la esperanza de que un compañero de equipo esté más cerca del líder del oponente para robar el disco.

los robar Estado debe ser cambiado (lineas 28 y 29) para permitir que los atletas empujen el defender Estado en esa situación:

class Athlete // (...) private function stealPuck (): void // ¿Tiene el puck algún dueño? if (getPuckOwner ()! = null) // Sí, lo tiene, pero ¿quién lo tiene? if (doesMyTeamHasThePuck ()) // Mi equipo tiene el puck, así que es hora de dejar de intentar robar // el puck y comenzar a atacar. mBrain.popState (); mBrain.pushState (ataque);  else // Un oponente tiene el puck. var aOpponentLeader: Athlete = getPuckOwner (); // ¿Está el oponente con el puck cerca de mí? if (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);   // (… ) 

Después de actualizar el robar En el estado, los atletas ahora pueden organizar tácticas de ataque y defensa, lo que hace que dos equipos controlados por la IA puedan jugar unos contra otros..

El resultado se demuestra a continuación:

Conclusión

En este tutorial, implementamos una táctica de defensa utilizada por los atletas para defender su objetivo de los oponentes. Entonces mejoramos el defender Estado al agregar algunas acciones de ataque, como intentar robar el puck del oponente, lo que hizo que la táctica de defensa se sintiera más natural y convincente..

También mejoramos la sensación del comportamiento de defensa al agregar un estado extremadamente simple pero poderoso, el patrulla. La idea es evitar que los atletas se queden quietos mientras defienden la meta de su equipo.

Y con eso, hemos creado un sistema AI completo para nuestro juego de hockey! 

Referencias

  • Sprite: Estadio de hockey en GraphicRiver
  • Sprites: jugadores de hockey por Taylor J Glidden