[IA] Steering Behaviors en XNA (I de II)
Los Steering Behaviors son formas de comportamiento autónomas para agentes de un videojuego. El concepto y definición de los mismos proviene de Craig Reynolds. En esta serie de artículos propondré una implementación para algunos de estos steering behaviors, intentando hacerlo con un diseño lo más desacoplado, flexible y extensible posible. Todo ello intenentando superar mi primera aventura en el ámbito en este post anterior.
En este "episodio" os ofrezco la implementación de estos steering behaviors (uso denominaciones en inglés, ya que son las usadas en el mundillo y las que os facilitarán encontrar más información si lo necesitáis). No entro demasiado en la definición funcional de cada steering behavior, ya que puede encontrarse en el blog de Craig Reynolds. Ahí va un pequeño resumen:
- Seek: Consiste en perseguir un objetivo o Target, intentando acercarse a él de forma directa.
- Flee: Huye del Target, alejándose de él.
- Arrive: El mismo behavior que el Seek, sólo que este reduce la velocidad suavemente antes de alcanzar el objetivo.
- Pursuit: Persigue al Target con mayor "inteligencia", es decir, en vez de acercarse de forma directa al objetivo, realizaremos una estimación de su posición futura teniendo en cuenta el vector de velocidad en cada momento.
- Evade: Al igual que el pursuit, intenta escapar del Target intentando estimar la posición futura del perseguidor, en lugar de alejarse de forma directa.
- Wander: El agente se desplaza de forma errática, calculando un punto aleatório del área de un círculo situado enfrente del agente.
Mis favoritos son el Pursuit, que con un sencillo algoritmo genera una sensación de "inteligencia", y el Wander, que nos permite tener un agente que se desplaza de forma totalmente autónoma. Otro elemento a destacar es el diseño de esta implementación. Creo que es bastante flexible, aunque seguro es mejorable. Permite fácilmente integrar una máquina de estados finitos, para que el agente pueda cambiar de behavior en cualquier momento. Además podrían solaparse varios steering behaviors en un mismo agente a la vez... (aunque no tiene sentido solapar un seek y un flee, la utilidad de esto la veremos en la siguiente "entrega").
En el siguiente diagrama vemos que la clase SteeringBehaviors tiene instancias de otras clases, que representan cada uno de los comportamientos. Esto lo he hecho así para dotar de mayor flexibilidad a la implementación, y hacer el código menos complejo y por tanto más fácil de entender, mantener y extender. Cuando utilizemos esta clase desde cualquier juego para nuestros agentes, deberemos añadirles el Behavior con el método sobrecargado AddBehavior (con una sobrecarga para cada tipo de Behavior), y posteriormente llamando al método Update. El método update, el solito se encargará de ejecutar todos los steering behaviors que correspondan al agente. ¿Fácil, verdad?

Todos los steerings tienen una estructura común, aunque sus especializaciones pueden contener distintos atributos y métodos, como muestra este diagrama de ejemplo (no se incluyen todos los behaviors que contiene el código):

Como siempre os dejo el código adjunto para que lo provéis/uséis a vuestra conveniencia. Este vídeo refleja el resultado de la ejecución del programa: