Personajes enemigos
En Unreal Engine, los PNJ y los enemigos generalmente se configuran de manera muy similar al jugador, en cuanto a que un enemigo tiene un controlador y un peón. En realidad, los enemigos y el jugador comparten algunas funciones en una clase base común, AParrotCharacterBase. En cuanto al juego Parrot, los árboles de comportamiento se usan para controlar el comportamiento del enemigo, por lo tanto, se utiliza la clase de controlador de IA para crear los controladores del enemigo. Comenzaremos con el blueprint de animación, ya que esa configuración es compartida entre enemigos.
Blueprints de animación de enemigos
Plantillas de blueprint de animación
En casos donde existan varias mallas esqueléticas que compartan necesidades idénticas para la animación, se puede crear algo llamado plantilla de blueprint de animación (consulta Animation Blueprint Linking). En este caso, hay cuatro tipos de enemigo: un esqueleto sin cabeza, un esqueleto, un tiburón y un tiburón jefe. Como todos comparten configuraciones idénticas para animación y esqueleto, podemos reutilizar una plantilla que implemente el gráfico de animación y gráfico de eventos para todos. Aquí puedes ver cómo configurar esta plantilla: Blueprints > Enemy > EnemyBase > ABT_EnemyBase. Luce similar al blueprint de animación del jugador porque las plantillas se configuran casi de la misma forma que el blueprint de animación.
Blueprints de animación
En este caso, toda la implementación se encuentra en la plantilla, mientras que las animaciones están ausentes porque la plantilla no hace referencia a un esqueleto específico. Cada uno de los enemigos tiene su propio blueprint de animación que deriva de la plantilla, y cada uno tiene asignado animaciones de esqueleto en las anulaciones de gráfico de animaciones. Puedes ver un ejemplo aquí: Blueprints > Enemy > HeadlessSkeleton > ABP_Enemy_HeadlessSkeleton.
Aquí debajo hemos seleccionado las animaciones apropiadas para la malla esquelética del esqueleto sin cabeza para cada estado de animación.
Peones enemigos
Los personajes enemigos de Parrot comparten muchas funciones con el jugador; específicamente, puntos de impactos y funciones similares (como la muerte). Esta implementación compartida se puede ver en AParrotCharacterBase. Para la implementación específica para enemigos, tenemos la subclase AParrotEnemyCharacterBase. Esta controla todas las implementaciones sobre qué sistema de patrulla funciona, cómo funciona el combate y más cosas. Puedes aprender más sobre cómo funciona el combate en la documentación de Combate en Parrot.
En esta configuración, los chequeos de impacto y daño de combate se hacen sobre el enemigo, y aquí se encuentra una implementación de cómo activar volúmenes en la clase base de blueprint: Blueprints > Enemy > EnemyBase > BP_EnemyCharacter_Base.
Esta implementación se realiza aquí y no se controla en la clase nativa de C++ porque los volúmenes de activación tienen que ser diferentes para cada enemigo debido a sus diferentes formas, tamaños y complejidades de mallas. Esto es necesario porque un volumen de activación que se hereda no puede ser modificado en la clase derivada.
Controlador de IA de los enemigos
Como ya se mencionó, los enemigos son controlados con árboles de comportamiento, así que hay una clase base derivada de AIController en AParrotEnemyAIControllerBase. Aquí verás una variedad de BlueprintImplementableEvents usados para enviar datos a la pizarra para que usen los árboles de comportamiento.
Puedes ver cómo el controlador de IA pasa datos al árbol de comportamiento y cómo controla la detección de la presencia de los jugadores en Blueprints > AI > EnemyBase > BP_EnemyController_Base.
Creación de IA con árboles de comportamiento
Unreal Engine ofrece una infraestructura poderosa y flexible para crear IA usando árboles de comportamiento. Puedes encontrar una guía de inicio rápido para configurar el texto modelo básico con algunos comportamientos en la Behavior Tree Quick Start Guide. Los resultados de esa guía son usados como base de la IA del enemigo y para realizar alteraciones para configurar los comportamientos necesarios.
Tenemos dos tareas del árbol de comportamiento, Blueprints > AI > EnemyBase > BTT_FindNextPatrol y Blueprints > AI > EnemyBase > BTT_AttackPlayer para brindar la funcionalidad básica necesaria para patrullar y atacar a los jugadores. Hay una pizarra compartida, Blueprints > AI > EnemyBase > BB_Enemy_Base, ya que la infraestructura para poder usar todas las características está presente en cada enemigo. Decidir qué funcionalidades usar para personalizar los comportamientos de los enemigos depende de la implementación del árbol de comportamiento.
Cada enemigo tiene una configuración de árbol de comportamiento diferente para que cada uno se comporte de manera diferente. Puedes echar un vistazo a los cuatro en las siguientes ubicaciones:
Blueprints> AI > HeadlessSkeleton > BT_HeadlessSkeleton
Blueprints > AI/Skeleton > BT_Skeleton
Blueprints > AI > Sharky > BT_Sharky
Blueprints > AI > BossShark > BT_Boss_Shark
Creación de un sistema de punto de ruta de patrullaje configurable
Para los enemigos, Parrot no quiere tener la misma funcionalidad de patrullaje que muestra la guía de árbol de comportamiento, que es donde la IA enemiga selecciona aleatoriamente un punto navegable en un radio cada 4 segundos. Lo que se quiere es que los enemigos sigan activamente una ruta de patrullaje ida y vuelta, como en muchos otros juegos de plataformas.
Para esto, Parrot ha creado su propio sistema que brinda la funcionalidad necesaria. Esto consiste en el UParrotEnemyPatrolRigComponent que puede ser colocado en la escena para crear una patrulla. Usa subobjetos predeterminados de clase para instanciar un spline. Este spline se utiliza para crear los puntos de ruta de patrulla, dos volúmenes de activación (usados para activar el comportamiento de la IA), y un visualizador en el editor que dibuja el orden de los puntos de ruta. El orden de los puntos de ruta permiten que la dirección de la ruta de patrulla pueda verse al momento de editar. Puedes ver los detalles de la implementación con C++ en UParrotEnemyPatrolRigComponent.
Esta implementación es un componente para que pueda acoplarse un rig de patrulla a cualquier actor en la escena. Esto permite colocar un rig sobre un objeto en movimiento, es decir que la patrulla permanecerá correctamente colocada en el espacio local. Para colocar un rig de patrulla que no esté acoplado a un actor existente en una escena, tenemos AParrotEnemyPatrolRigActor, que es un actor que puedes colocar en cualquier parte de la escena y genera un UParrotEnemyPatrolRigComponent como subobjeto predeterminado sobre sí mismo.
Esta implementación permite seleccionar un enemigo para que sea generado en tiempo de ejecución y que siga la ruta de patrulla. Este proceso utiliza una característica de Unreal Engine llamada generación de actor diferida, que permite generar un actor en dos etapas: primero construye el objeto actor sin realizar ninguna inicialización AActor como BeginPlay. Esto te permite realizar configuraciones o ajustes necesarios para el actor antes de que sea inicializado. Después de realizar esta configuración, invocas a la segunda etapa para que finalice la generación e inicialice al actor. Esto se hace para el rig de patrulla para que cuando sea generado el actor enemigo, el spline de patrulla y los volúmenes de activación puedan ser conectados al actor para que puedan ser procesados durante la inicialización del actor y para que la secuencia de patrulla pueda comenzar automáticamente.
Puedes ver el código que realiza la generación de actor diferida en UParrotEnemyPatrolRigComponent. Existe una característica similar en blueprint, donde puedes etiquetar propiedades en un actor de blueprint como Exponer al generar, que te permite pasar argumentos al nodo de generación de blueprint, que se establecen antes de que tenga lugar la inicialización del actor.
Debajo, puedes ver un ejemplo de cómo se configura uno de estos rigs de patrulla en Maps > Level_1 > Level_1 con un rig de patrulla de dos puntos, comenzando en el punto 0 a la derecha. Este rig de patrulla está configurado para generar un BP_EnemyCharacter_Skeleton.
Debajo hay un menú de Indicadores para identificar los puntos de ruta de rig de patrulla para identificar fácilmente al momento de editar. La mayoría de las casillas de verificación de indicadores están seleccionadas. Puedes ver los detalles de cómo se implementa esto en el componente de visualizador en el editor, UParrotPatrolRigDebugVisualizer.