Archivo de la etiqueta: sound cue

Cómo causar daño a un personaje en UE4 – Parte 2

En el tutorial pasado vimos una introducción al AnimComposite y el AnimMontage en Unreal Engine 4 y dejamos a nuestro personaje con las habilidades necesarias para dar puñetazos. En este tutorial vamos a usar esas habilidades para golpear a otro personaje, causándole daño hasta que su salud llegue a 0 y muera.

Este simple ejemplo nos permitirá ver varias cosas nuevas:

– Introducción a los mecanismo de colisión que nos brinda UE4
– El uso del MarketPlace.
– El uso del Construction Script en los blueprints
– Cómo aplicar daño a un personaje
– Introducción al trabajo con efectos de sonido en Unreal Engine 4
– Cómo reproducir un AnimSequence directamente desde código
– Como eliminar un Actor del nivel cuando ya no se va a usar más

Y muchas cosas más 😉 … así que, manos a la obra !!

Introducción a los mecanismos de colisión en Unreal Engine 4

En el segundo tutorial vimos un ejemplo simple del trabajo con las colisiones entre dos objetos, cuando implementamos la funcionalidad para que el personaje pudiera recolectar las monedas dispersas por el terreo. Vamos en este tutorial a profundizar un poco en la teoría detrás de las colisiones en UE4.

Unreal Engine 4 tiene un potente y flexible mecanismo para el manejo de colisiones entre los elementos del juego. Cada objeto que puede colisionar con otro es de un “Object Type“ y se le define cómo responderá a la colisión con los otros Object Types de tres formas distintas: si lo Ignorará, si se superpondrán o si lo bloqueará. Los Object Types existentes son:

WorldStatic: Los Volúmenes existentes en el juego, y los objetos estáticos del nivel, por ejemplo: Una piedra o una pared deben ser WorldStatic

WorldDynamic: Los Actores dinámicos (los que se mueven) a parte a los Pawn, PhysicsBodies y Vehicles (que son Objet Type específicos). Serían por ejemplo, una plataforma que se mueve de un lado a otro, un elevador, etc.

Pawn: Los personajes, estos ya los conoces 😉

PhysicsBody: Los objetos físicos. El trabajo con objetos físicos los veremos en próximos tutoriales. Básicamente son objetos que se les puede definir para que se comporten físicamente real. Por ejemplo, que los afecta la gravedad, su masa, fuerzas o impulsos que se les aplica, etc. Los objetos de este tipo en el nivel deben tener como Object Type, PhysicsBody.

Vehicle: Este es bastante claro, no ? :) .

Destructible: Actores destructibles. Estos los veremos también en próximos tutoriales y de seguro te va a encantar jugar un poco con ellos. Básicamente son objetos que los podemos configurar para que se fraccionen y se rompan cuando reciban un impacto, un efecto genial y que siempre gusta mucho.

Bien, ya sabemos los distintos Object Type que nos da UE4, ahora vamos a investigar un poco como está configurado por defecto nuestro personaje protagónico para responder a las colisiones. Abre el Blueprint del personaje, selecciona el modo Components y selecciona el componente [ROOT]CapsuleComponent. En el panel de detalles muévete hasta la sección Collision y despliega la propiedad Collision Presets.

Blueprint del personaje en el modo Components donde se muestra la configuración de Collision del [ROOT] CapsuleComponent

Blueprint del personaje en el modo Components donde se muestra la configuración de Collision del [ROOT] CapsuleComponent

 

Desde esta sección podemos configurar el Object Type de este objeto y cómo reaccionará a las colisiones con los otros elementos del juego. Fíjate en la propiedad Collision Presets, en este caso tiene seleccionado Pawn. El UE4 por defecto nos trae un grupo de configuraciones predefinidas que son comunes en los juegos y que podemos seleccionar, y así no tenemos que configurar siempre manualmente como reaccionará este objeto con los otros con los que colisione. Si expandes esta sección verás que todas las propiedades están bloqueadas y con una configuración predefinida, prueba variar la selección de Collision Presets a otro que no sea Pawn, notarás que cambia la configuración. Por supuesto, siempre podemos seleccionar Custom … y settear la configuración que queramos específicamente para cada Object Type.

La configuración de colisión que tiene el CapsuleComponent del personaje, predefinida por el Preset Pawn es la siguiente:

Primero tenemos la propiedad Collision Enabled en la que se pueden seleccionar tres posibles valores:

No Collision: Cero colisión, son ignoradas totalmente las colisiones en las que interviene este objeto.
No Physics Collision: Las colisiones de este objeto solo se tienen en cuenta para raycasts y overlaps (los veremos más adelante)
Collision Enabled: Para responder a ambos tipos de colisiones: con simulación física y sin ella.

Debajo tenemos el Object Type para definirle a este elemento. En este caso es Pawn.

A continuación tenemos una especie de tabla. Las filas son cada uno de los Object Type y cada columna representa un tipo de Collision Response que tenemos para reaccionar a una colisión, estos son:

Ignore: Ignorará completamente la colisión. Lo que quiere decir que para el Object Type que se le marque Ignore, cuando este objeto colisione con él, ignorará por completo esto y lo traspasará.

Overlap: Overlap es igual a Ignore, o sea, los objetos se traspasan, pero este tiene una particularidad. Si te fijas, al inicio de la sección Collision tenemos dos atributos a marcar. Simulation Generate Hit Event y Generate Overlap Event. Si le marcamos para un determinado Object Type que maneja la colisión con Overlap estos se traspasarán, pero si la opción Generate Overlap Event está en true, en el momento de la colisión se generará un evento que podemos intervenir desde el Blueprint o C++ y ejecutar una acción determinada. Veremos un uso de esto más adelante. Además de la opción Generate Overlap Events tenemos la propiedad Simulation Generate Hit Events. Este check es semejante al otro pero lo usamos cuando el objeto es físico. Habilita para que se generen eventos de tipo Hit cuando el objeto físico colisiona con otro. Veremos su utilidad en próximos tutoriales.

Block: Con el objeto que se defina para que responda a la colisión con Block no podrá ser atravesado. En el caso de la cápsula de colisión del Pawn verás que para todos los Object Type el Collision Response está en Block, para evitar que el personaje atraviese las cosas.

Por último, un detalle importante, fíjate que las filas están separadas en dos bloques Trace Response y Object Response. El primero nos permite definir como reaccionará el objeto a las colisiones con los Traces, estos son básicamente rayos invisibles que podemos usar para determinar si algún objeto colisiona con ese rayo y tiene montón de utilidades. Veremos uso de estos en próximos tutoriales.

Te recomiendo que le dediques un tiempo a revisar la configuración de colisión para cada uno de los Collision Presets y además la configuración de colisión para cada uno de los componentes del personaje, otra configuración importante a tener en cuenta y entender es la del Mesh del personaje que usa como Collision Presets: CharacterMesh

Configuración de las propiedades de Collision para el Mesh del personaje.

Configuración de las propiedades de Collision para el Mesh del personaje.

 

Muy bien, ya con esta teoría de nuestro lado, podemos pasar a implementar la funcionalidad para poder golpear al lanzar un puñetazo. La lógica detrás de esto sería: detectar cuando el puño colisiona con el otro personaje y en ese momento implementar lo necesario para reaccionar al golpe. Vamos a agregar al nivel otro personaje que nos servirá como monigote para practicar nuestros golpes.

Con los recursos que tenemos ahora mismo, poco podemos hacer, pero aquí viene otro de los enormes regalos que tenemos al usar Unreal Engine: El Marketplace !!. El equipo de Epic, por si fuera poco el poner este fenomenal motor en nuestras manos, también nos brinda acceso al MarketPlace, la zona en donde podrás encontrar una enorme cantidad de recursos para tus proyectos, tus prototipos para aprender, etc. Es un lugar que al menos todas las semanas deberías darle un recorrido para ver que te trae de nuevo.

Introducción al Marketplace

Para usar el Marketplace tienes que tener tu subscripción válida y el Unreal Launcher, que si no lo tienes, lo puedes descargar haciendo clic en el editor en la barra superior en el botón MarketPlace:

tuto6_imagen_01

Una vez que abras el Unreal Launcher tendrás la pantalla de login. Pon tu usuario y password y … “Bienvenido al paraíso“ !! :)

Captura del Marketplace

Captura del Marketplace

 

Tómate unos minutos y revísalo, veras el montón de cosas que encontrarás, de seguro lo querrás bajar todo :) .. . . sí, es verdad, no todo es gratis, de hecho, la mayoría de las cosas son de pago, pero vamos !! mira el precio y compáralo con todo el trabajo que te ahorrarás, la ventaja es enorme !!. De cualquier forma, no te preocupes, lo que vamos a necesitar en nuestros tutoriales es gratis :). Busca aquí el Animation Pack y descárgalo (está marcado en rojo en la imagen anterior). El Animation Pack es un paquete con un montón de animaciones con el mismo modelo que estamos usando en nuestros tutoriales.

Después de descargarlo, en la sección de Library podrás tener acceso a todo lo que descargues y desde ahí lo podrás agregar al proyecto. Agrega el Animation Pack al proyecto, verás que se te creará en el Content Browser una carpeta de nombre AnimStarterPack y dentro de ella, todo el contenido de este paquete. Tómate unos minutos y abre cada una de las animaciones para que veas todo lo que tenemos ahora para nuestros tutos :). Dentro de la carpeta AnimStarterPack además de las animaciones ya importadas tendrás la carpeta Character. Dentro de esta carpeta está el Blueprint, el AnimBlueprint el Skeletal Mesh y el resto de los recursos necesarios. Aunque de momento no usaremos el Blueprint del Character que trae por defecto el AnimStarterPack te recomiendo que le des un vistazo y lo estudies un poquito.

Creando un personaje para golpear

Voy a pasar por estos pasos bastante rápido, porque si has seguido los tutoriales no tendrás problema en hacer esto por tu cuenta.

Crea una carpeta en el Content Browser que se llame BlueEnemy. Crea un nuevo Blueprint que herede de Character y ponle de nombre BlueEnemyBlueprint. Crea un AnimationBlueprint para el esqueleto HeroTPP_Skeleton que está en /Game/AnimStarterPack y ponle BlueEnemyAnimBlueprint de nombre. Ahora abre el BlueEnemyBlueprint selecciona el Modo Default y define el Mesh de este Character con el Mesh del AnimStarterPack y el Animation Mode en Use Animation Blueprint y el BlueEnemyAnimBlueprint que acabamos de crear.

Modo Default del BlueEnemyBlueprint

Modo Default del BlueEnemyBlueprint

 

Pasa ahora para la sección Components y mueve el Mesh para que quede dentro de la cápsula y en la dirección correcta

Modo Components del BlueEnemyBlueprint

Modo Components del BlueEnemyBlueprint

 

Ahora pasa al modo Graph para abrir el Blueprint de este personaje y créale una variables nueva de nombre Health y de tipo INT y en valor por defecto ponle 100. Fíjate un detallito interesante, al crear una variable desde el blueprint puedes definirle un Tooltip. Este Tootip es un texto descriptivo para la variable que se ve cuando se pone el cursor sobre ella en el panel My Blueprint.

La variable Health será quien defina la salud de este personaje, cada vez que le demos un puñetazo perderá salud hasta que el valor de esta variable llegue a cero, cuando llega a cero muere.

Ahora abre el AnimationBlueprint para este personaje y crea una maquina de estado súper simple, solo con el estado Idle.

Maquina de estado muy simple para el BlueEnemyCharacter

Maquina de estado muy simple para el BlueEnemyCharacter

 

Vamos a aprovechar esta situación para poner otro ejemplo del recién aprendido AnimMontage. En realidad esto que haremos no es necesariamente con el AnimMontage, pero creo que va bien practicar un poquito lo que acabamos de aprender para que se pegue, por eso vamos a hacerlo así :) Crea un nuevo AnimMontage como lo vimos en el tutorial pasado, dale de nombre HitAnimMontage y agrégale las animaciones Hit_React_1, Hit_React_2 y Hit_React_3 que tenemos en el AnimStarterKit. Configúralo para que te quede de la siguiente forma:

HitAnimMontage que usaremos para reproducir aleatoriamente una animación de impacto en el personaje cada vez que reciba un puñetazo.

HitAnimMontage que usaremos para reproducir aleatoriamente una animación de impacto en el personaje cada vez que reciba un puñetazo.

 

Por último modifica el AnimGraph para agregarle este Slot entre el State Machine y el Final Animation Pose.

tuto6_imagen_10

Ya tenemos todo lo necesario para jugar un poco con este personaje medio monigote y digo medio monigote porque básicamente lo que hará es estar en reposo, cuando reciba un puñetazo expresará su dolor reproduciendo una animación y cuando su salud llegue a cero morirá.

Para poder ver bien las colisiones entre ambos personajes podemos usar un pequeño truco. Abre el BlueEnemyBlueprint selecciona el modo Componentes, selecciona [ROOT]Capsule Component y en el panel detalles muévete hasta la sección Rendering y desmarca la propiedad Hidden In Game. Has esto mismo para el personaje protagónico. Esto nos ayudará a ver en tiempo de ejecución esta cápsula y nos ayuda a revisar en detalles las colisiones.

Pero antes de probar esto, tenemos un detallito. El componente que tiene este personaje para colisionar y bloquear a los objetos, es una cápsula. En nuestro juego solo nos desplazamos en un solo eje, pero cuando caminas hacia este otro personaje y comienzan a colisionar y a bloquearse, si intentas seguir caminando nuestro personaje patinará alrededor de la cápsula rompiendo el modo de desplazamiento de nuestro scroll-side. Pruébalo para que lo veas mejor. Para evitar esto, lo que hice fue agregar un Box Component al personaje que encierre a la cápsula y las propiedades de colisión las configuro igual a la cápsula, con el Preset: Pawn. Con esto, al ser recta la cara de la caja, se evita el problema del desplazamiento forzado.

Listo !!, agrega este personaje al escenario, recuerda que como nuestro juego es un scroll side y el personaje principal solamente se mueve hacia la derecha o la izquierda en un solo eje, para que se puedan encontrar ambos tienen que estar alineados.

Guarda, compila, ejecuta el juego y muévete en dirección al BlueEnemy. Cuando los dos componentes llegan a colisionar, ya no te puedes mover más. Si recuerdas cuando miramos la configuración de colisión para la cápsula, esta tiene marcado como Collision Response para todos los elementos: BLOCK. Por eso es que al colisionar estos dos elementos no se pueden traspasar.

Ambos personajes en el punto donde colisionan los componentes que los encierran. Como ambos están configurados como Block, aunque intentes seguir moviéndote en esa dirección no podrás avanzar más.

Ambos personajes en el punto donde colisionan los componentes que los encierran. Como ambos están configurados como Block, aunque intentes seguir moviéndote en esa dirección no podrás avanzar más.

 

Bien, eso está perfecto. . . ahora, lanza un puñetazo presionando la tecla R. Como notarás, no pasará absolutamente nada, y en este caso la mano traspasa el Mesh del otro personaje. Tenemos que lograr detectar la colisión del puño del personaje con el Mesh del enemigo. Para esto vamos a irnos por una solución muy simple, pero suficiente para nuestro juego. Dicho sea de paso, esta solución fue tomada del los video-tutoriales de Epic Games que te comenté en el tutorial pasado y que aprovecho para recomendártelos de nuevo :)

Vamos a agregar dos esferas que estarán ancladas a los puños del personaje. Cuando se detecte la colisión de una de esas esferas con el Mesh del otro personaje, es que estamos golpeándolo.

Agregando dos Sphere Components anclados a las manos del personaje para detectar la colisión cuando se lance un puñetazo.

Abre el Blueprint de nuestro héroe en el modo Components. Fíjate que en el panel Components encima de la jerarquía de componentes que forman parte de nuestro personaje, hay un ComboBox que dice Add Component. Desde este combobox podemos agregar nuevos componentes al personaje. Despliégalo y selecciona una Sphere, repite el proceso y agrega otra. Mueve las esferas para que queden más o menos sobre cada una de las manos del personaje, no te tiene que quedar perfecto esto es solo temporal. Cámbiale los nombres a esos componentes a PunchRightComponent y PunchLeftComponent. Puedes seleccionar las dos dando clic en una y con la tecla Ctrl presionada da clic en la otra. De esta forma podrás modificar una misma propiedad en ambos componentes al mismo tiempo. Muévete en el panel Details a la sección Rendering y desmárcale Hidden in Game. En la sección Shape, a la propiedad Sphere radius dale el valor de 15. Recuerda que el Hidden In Game es temporal, solo para poder ver el componente en el juego y poder revisar mejor las colisiones.

Blueprint del personaje principal en el modo Components con las dos esferas agregadas

Blueprint del personaje principal en el modo Components con las dos esferas agregadas

 

En este punto las esferas están agregadas como componente del personaje, pero tenemos que anclarlas a las manos del mismo para que se muevan junto con estas cuando se lance el puñetazo.

Hasta ahora solo hemos usado la hoja Event Graph del blueprint del personaje, pero como ya habrás notado, también contamos con una hoja en blanco de nombre Construction Script. Todo algoritmo que programemos aquí mediante visualscript se ejecutará en la construcción del objeto. Vendría jugando como el papel del constructor de nuestra clase. Modifícalo para que te quede de la siguiente forma:

Construction Script del HeroCharacterBlueprint para anclar los PunchComponents a los huesos de la mano del personaje.

Construction Script del HeroCharacterBlueprint para anclar los PunchComponents a los huesos de la mano del personaje.

 

Es simple lo que hacemos aquí, incluso ya lo habíamos hecho anteriormente pero desde C++. Hacemos un AttachTo de un componente a otro, como mismo hicimos con la cámara y el SpringArm en el segundo tutorial. El nodo Attach To nos permite anclar un componente a otro y le podemos especificar también el Socket al que lo anclaremos. Todo lo relacionado con los Sockets lo veremos en próximos tutoriales, de momento vasta con saber que son puntos en el objeto que podemos usarlos para anclar otro objeto. Fíjate que en el parámetro In Socket Name escribimos directamente hand_l y hand_r para cada uno de las esferas . . . uuumm, de seguro te imaginas que es esto eh ? 😉 . . . pues sí, podemos usar como socket, cualquiera de los huesos del esqueleto que usa este Mesh. Si abres el esqueleto de este personaje verás que los huesos de la mano se llaman hand_l y hand_r .

El último parámetro del nodo AttachTo es el Attach Type y nos permite definir mediante tres valores de enum como se afectará la posición y rotación de este elemento respecto al padre. En nuestro caso queremos que lo siga totalmente, así que selecciona la opción Snap to Target.

En este punto me gustaría comentarte algo. Este es el tipo de cosas que yo en lo personal prefiero hacerlas en C++, de hecho, si te fijas en nuestra clase Character toda la creación de los componentes y los Attach To los hacemos desde C++. Quise en este tutorial hacerlo mediante blueprint para ver un ejemplo de esta vía. Un muy buen ejercicio para que sigas logrando soltura con el framework de clases es que intentes hacer esto mismo pero desde C++ … y esta vez no te dejaré ninguna pista :)

Pues bien, compila, guarda y pasa al modo Components, verás que ahora salen las esferas ancladas perfectamente a las manos del personaje. Esto pasó porque al compilar se ejecuta el construction script y esta sección de componentes se actualiza. Genial verdad !?

Modo Components del Blueprint del Character con los PunchComponents anclados a la mano del personaje.

Modo Components del Blueprint del Character con los PunchComponents anclados a la mano del personaje.

 

Muy bien, casi terminamos aquí, solo nos queda un detalle. Para detectar la colisión entre este personaje y el enemigo vamos a usar el Evento Overlap que hablamos al inicio. O sea, podemos saber cuando dos elementos se superponen y lanzar un evento en ese preciso momento, es esa la técnica que vamos a usar para detectar cuando golpeamos al otro personaje, pero para hacer esto bien, tenemos que hacer una modificación en las propiedades de colisión de ambos PunchComponents.

Selecciona los dos, PunchRightComponent y PunchLeftComponent desde el modo Components del Blueprint del personaje y en Collision Presets selecciona OverlapAll y desmarca el check: Generate Overlap Event. Pero te preguntarás ¿Porqué desmarcar esta opción sin en realidad necesitamos que se dispare el evento cuando se detecte el overlap?. Esto es verdad, pero si desde ahora dejamos esto en true, constantemente estos componentes generarían el evento y si por ejemplo se pasa por al lado del personaje aunque sea caminando, se dispararía el evento. Como es lógico, no es esto lo que queremos, solo queremos que se detecte el evento si se está golpeando. Por lo que dinámicamente vamos a poner esta propiedad en true para cada brazo en el momento preciso y para esto vamos a usar los BranchPoints que tenemos definido en el PunchingAnimMontage.

Abre el PunchingAnimMontage y fíjate que tenemos dos BranchPoints que creamos en el tutorial pasado. Ajusta la posición de cada BranchPoint más o menos a la mitad de la animación si no lo tienes así:

tuto6_imagen_12.1

Si te fijas con el timeline de la animación, cada evento se dispararía ya cuando vamos a dar el golpe y en este punto es cuando activaremos el Generate Overlap Event de la mano correspondiente y desactivamos el de la otra mano.

Abre ahora el AnimationBlueprint del personaje y modifica donde intervenimos estos eventos para que te quede de la siguiente forma:

Trozo del AnimationBlueprint de nuestro personaje donde intervenimos el evento de los BranchPoint del PunchingAnimMontage y agregamos para activar o desactivar según corresponda la propiedad Generate Overlap Event de los PunchComponents.

Trozo del AnimationBlueprint de nuestro personaje donde intervenimos el evento de los BranchPoint del PunchingAnimMontage y agregamos para activar o desactivar según corresponda la propiedad Generate Overlap Event de los PunchComponents.

 

Por último, para que el evento se dispare, necesitamos habilitar el Generate Overlap Event también en el otro personaje. Abre el BlueEnemyBlueprint en el Modo Components selecciona el Mesh y márcale la propiedad Generate Overlap Event ya que queremos detectar cuando uno de los dos PunchComponents del personaje colisiona con el Mesh de este otro.

BlueEnemyBlueprint en modo Components con la propiedad Generate Overlap Event para el Mesh en true.

BlueEnemyBlueprint en modo Components con la propiedad Generate Overlap Event para el Mesh en true.

 

Listo !! esto es todo lo que necesitamos para detectar la colisión. Vamos ahora a implementar la lógica de lo que pasa en ese momento.

Causando daño al disparar el evento Overlap entre uno de los dos PunchComponents del personaje principal y el Mesh de este otro personaje.

Vamos a intervenir el evento Overlap e implementar lo necesario para causar daño. Desde el BlueEnemyBlueprint en el modo Components selecciona el Mesh y en el panel de detalles muévete hasta la sección Events. Fíjate que esta sección tiene un combobox que dice Add Event, si lo despliegas se listan todos los eventos de este componente que podemos usar desde código.

Agregando el evento OnComponentBeginOverlap al EventGraph desde el modo Components

Agregando el evento OnComponentBeginOverlap al EventGraph desde el modo Components

 

Da clic en Add OnComponentBeginOverlap. Esto agregará el nodo OnComponentBeginOverlap (Mesh) al EventGraph. Ahora modifica el EventGraph para que te quede de la siguiente forma:

EventGraph del BlueEnemyBlueprint donde se aplica daño al personaje cuando se dispare el método Begin Overlap en el Mesh.

EventGraph del BlueEnemyBlueprint donde se aplica daño al personaje cuando se dispare el método Begin Overlap en el Mesh.

 

Aquí viene lo interesante. Cuando se dispara el método BeginOverlap en el Mesh se usa el nodo Apply Damage para aplicarle un daño a este personaje. Este nodo es súper útil, espera como parámetro cual será el actor al que se le aplicará el daño. En este caso es este mismo actor, por lo que usamos la variable self. Además, permite definirle un valor numérico de daño, en este caso le pasamos directamente 20, pero pudiéramos usar una variable para darle el valor dinámicamente. Los otros tres parámetros son opcionales y pueden resultar muy útiles. Event Instigator se usa para definir el Controller que causa el daño. Damage Causer se usa para definir el actor que causa el daño, por ejemplo, en nuestro caso pudiéramos pasar como parámetro una referencia de nuestro personaje y por último, Damage Type Class nos permite definir una clase con propiedades específicas para extender la información del daño aplicado.

Es importante en este punto aclarar que para poder usar el método Apply Damage en un Actor este tiene que tener la propiedad Can be Damaged en true. Por defecto el character la tiene en true, puedes verlo en el Modo Defaults en la sección Actor.

Por último, para probar lo que hemos hecho, agregamos un nodo Print String que nos permite imprimir el texto PUNCH ! en la pantalla.

Listo !! compila, guarda y ejecuta el juego. Acércate al otro personaje y lanza un puñetazo con la tecla R.

Captura del juego en ejecución en el preciso momento donde se lanza el evento OnComponentBeginOverlap al colisionar el PunchRightComponent con el Mesh del otro personaje.

Captura del juego en ejecución en el preciso momento donde se lanza el evento OnComponentBeginOverlap al colisionar el PunchRightComponent con el Mesh del otro personaje.

 

Perfecto !!, ya tenemos el momento en donde colisiona el puño con el Mesh del otro personaje y en ese punto aplicamos un daño. . . pues bien, una de las ventajas que tenemos al usar el método Apply Damage es que al aplicar un daño se lanza un evento que podemos intervenir para implementar toda la lógica cuando un personaje recibe el daño.

Vamos a intervenir este evento en el blueprint e implementar todo lo necesario para restar la salud del personaje según el daño que recibió hasta que su salud llegue a cero y muera. Pero antes de eso nos falta una cosa. Queremos que cuando el personaje reciba el golpe se reproduzca un efecto de sonido y cuando muera se reproduzca otro efecto. Vamos a usar este pretexto para tener nuestro primer acercamiento al trabajo con sonidos en Unreal Engine 4.

Introducción al trabajo con efectos de sonido en Unreal Engine 4

La música y los efectos de sonidos pueden marcar la diferencia y ser los responsables de que te quedes “como bobo“ delante de un juego. Me pasó con el Rayman Legends y hace poco con el Valiant Hearts: The Great War al escuchar su música. Por cierto, dos juegos que por nada del mundo te puedes perder :)

En Unreal Engine 4 todo lo referente al trabajo con audio se maneja dentro de unos objetos llamados Sounds Cues. Un Sound Cue se puede ver como un blueprint orientado a audio. O sea, siguiendo la misma filosofía del blueprint, del trabajo con nodos, la asociación de un nodo a otro etc, se pueden crear complejos efectos de sonido, mescla entre efectos y muchas cosas más relacionadas con el audio para nuestro juego. Al final este Sound Cue lo podemos tratar como un efecto por si solo.

Vamos a ver un simple ejemplo del trabajo con efectos de audio en UE4. Importa desde el Content Browser estos tres archivos. Son tres efectos cualesquiera para reproducir cuando el BlueEnemy reciba los golpes, puedes usar unos tuyos si los tienes a mano.

En estos momento Unreal Engine 4 solo permite importar archivos de sonido WAV de 16bits con especificaciones PCM, ADPCM, DVI ADPCM y cualquier sample rate, aunque recomiendan 44100 Hz o 22050 Hz.

Desde el Content Browser selecciona el botón Import e importa estos tres ficheros. Verás que se te muestran como Sound Wave. Puedes reproducir cada uno dando clic derecho sobre él y seleccionando la opción Play en el menú que se despliega. Desde el código se pueden reproducir estos Sound Wave directamente sin problema, pero en muchos casos queremos procesar el efecto antes de reproducirlo directamente y para esto es que usamos los Sound Cue. Vamos a ver ambos casos: Crearemos un Sound Cue para hacer que se reproduzca aleatoriamente uno de estos efectos cada vez que el personaje reciba un golpe y cuando muera reproduciremos directamente el tercero, así mismo como Sound Wave.

Para crear un Sound Cue vasta con dar clic derecho en el Content Browser y seleccionar Sounds/Sound Cue. Esto te crea un nuevo ítem de tipo Sound Cue en los recursos del proyecto y te abre directamente el Sound Cue Editor. Por defecto el Sound Cue tiene un nodo Output que representa el resultado final de todo el pre-procesamiento que se haga, como el Final Animation Pose para el caso de las animaciones. Desde aquí, solamente con nodos, podrás crear complejos efectos de sonidos, para que tengas una idea, da clic derecho en una zona en blanco y lee todas las opciones de nodos que puedes crear. Tomate un tiempo y date un recorrido general por el editor para que lo conozcas un poco. Honestamente, de este editor yo solo se lo súper básico ya que no es mi campo, pero estoy seguro que un profesional en el tema lo exprime por completo :)

Bueno, a lo nuestro, selecciona primero del Content Browser dos de los efectos, recuerda que puedes usar la tecla Ctrl para selección múltiple. Con los dos Sound Waves seleccionados abre el Sound Cue, da clic derecho en una zona en blanco y selecciona de la sección From Selected, la opción Random: Multiple WAVs y conecta la salida del nodo Random a la entrada del Output. Te quedará de la siguiente forma:

Sound Cue para reproducir aleatoriamente uno de los dos efectos de sonido.

Sound Cue para reproducir aleatoriamente uno de los dos efectos de sonido.

Con esto acabamos de crear un Sound Cue que podemos manejar como un efecto de sonido normal, pero al decirle que se reproduzca, él sólo se encargará de seleccionar aleatoriamente uno de estos dos efectos y reproducirlo. Súper verdad !! ?

Pues ya con esto estamos listo para retomar la implementación de lo que pasa cuando el personaje recibe el daño.

Interviniendo el evento Any Damage para implementar lo necesario cuando el BlueEnemy recibe el daño por un puñetazo.

Muévete a una zona en blanco del BlueEnemyBlueprint e implementa el siguiente algoritmo

Algoritmo cuando el BlueEnemy recibe daño.

Algoritmo cuando el BlueEnemy recibe daño.

 

Muy bien, vamos con detenimiento por todo este algoritmo porque en él usamos varios nodos que no habíamos usado antes. Primero agregamos el Nodo Event Any Damage. Este evento se dispara cuando este actor recibe daño. En este caso se dispararía cuando se detecta la colisión con el puño del personaje y se llama al Apply damage.

Fíjate que desde este evento podemos obtener el valor de daño aplicado, recuerda que en nuestro caso es 20, además podemos obtener el Damage Type, el Instigate By y el Damage Causer que como vimos, se pueden pasar como parámetros al Apply Damage.

Lo primero que hacemos es restarle la cantidad de daño aplicado a la variable Health que definimos para este personaje para representar su salud y que inicialmente está en 100. El nodo Clamp nos permite limitar el valor entre dos extremos. En este caso 0 y 100, para evitar que al finalizar la operación la variable tome valor menor que 0 o mayor que 100 en caso que fuera posible.

Después de actualizar el valor de la variable Health, usamos un Print String para ayudarnos a ver lo que pasa en cada momento. Usamos un nodo muy útil para el trabajo con strings, el nodo Append, que nos permite unir dos strings. En este caso unimos los strings “Blue Enemy Health” y el valor de la variable Health, fíjate que si intentas conectar la variable Health al puerto B del Append, como son dos variables de tipo de dato distinto, el editor automáticamente nos genera un nodo por el medio que convierte el tipo de dato int de la variable Health a string para poderlo usar con Append.

Después de eso tenemos una condición usando el nodo Branch. Preguntamos si la variable Health llegó a cero. Si es false, es que al personaje aún le queda salud y en este caso reproducimos una animación simple para reflejar el golpe. Fíjate que aquí usamos otra ventaja de los Montage. Recuerdas que en el HitAnimMontage que definimos tenemos tres secciones con tres animaciones de hit distintas que se llaman HitReact1, HitReact2 y HitReact3, verdad ? Pues aquí con el nodo Random Integer in Rage generamos un número aleatorio entre 1 y 3 creamos un string mediante el Append uniendo el string ”HitReact” con el número generado, y de esta forma obtenemos aleatoriamente el nombre de una de las secciones definidas en el AnimMontage. Por último usamos el nodo Play Anim Montage para reproducir la animación y le pasamos por el parámetro Start Section name el string generado. De esta “curiosa“ forma y con la ventaja que nos brindan los AnimMontage, cada vez que el personaje reciba un golpe tendrá una animación aleatoria para reaccionar al golpe

Por último reproducimos el Sound Cue que creamos hace unos minutos y que vimos que sería aleatoriamente uno de los dos efectos de dolor. Para esto usamos el nodo Play Sound at Location. Este nodo espera dos parámetros. El parámetro Sound que es el archivo de sonido a reproducir puede ser directamente aun Sound Wave o un Sound Cue, y el segundo parámetro nos permite definir la posición en el mundo 3D en la que se reproducirá el sonido. En este caso le pasamos la posición de este personaje.

La otra rama del Branch es cuando la variable Health llega a cero, que significa que ese último golpe mató al personaje. Pues bien, para este caso lo primero que hacemos es reproducir una animación de muerte. Pero fíjate que usamos un nuevo nodo para reproducir una animación. El nodo Play Animation nos permite reproducir un AnimSequence directamente sin tener que hacer uso del AnimationBlueprint o de los AnimMontage. El parámetro Looping tiene que estar en false, ya que queremos que esta animación se reproduzca una sola vez y quede ahí en el último frame.

También reproducimos un efecto de sonido, en este caso un Sound Wave directo, solo a modo de demostración.

Por último, hay un detalle. Si pruebas en este momento verás que todo va de maravillas pero cuando tumbas al otro personaje con el último golpe, este caerá al suelo con su animación, pero se quedarán en el medio del camino los dos componentes de colisión, la capsula y la caja. Para solucionar esto, seguido a la reproducción del efecto de sonido usamos el nodo Destroy Component que nos permite destruir un componente determinado y le pasamos el Capsule Component y el BoxComponent. Otra solución puede ser desactivarle la colisión, en vez de destruir por completo el componente.

Seguidamente, usamos el nodo Delay para demorar el algoritmo 3 segundos y por último destruimos completamente el actor de la escena. Esto provocará que después de tumbar al personaje pasaran tres segundos y su cuerpo desaparecerá del nivel.

Listo !!, compila, guarda y ejecuta el juego. Muévete hasta donde está el otro personaje y comienza a golpearlo. Verás que cada vez que le damos un puñetazo lanza una de las animaciones de impacto y cuando su salud llega a cero termina con la animación de muerte. Puedes ver con la ayuda de los Print String como disminuye la salud del otro personaje de 20 en 20 ….

Si, si, si !! . . . se que ahora mismo debes estar fijándote en que las animaciones cuando el personaje recibe un golpe están terribles, con la reacción del personaje parece más a que le están haciendo cosquillas :), pero son las animaciones que tenemos a mano :( . . . ya en nuestro juego, que el equipo de animación nos haga algo mejor :)

Captura del juego cuando el personaje le da el último puñetazo al enemigo y lo derriba.

Captura del juego cuando el personaje le da el último puñetazo al enemigo y lo derriba.

 

Conclusión

Vamos terminando aquí este tutorial, espero que te hayas divertido dándole puñetazos al BlueEnemy :). Si eres de los que prefiere el trabajo con C++ (como yo) un buen ejercicio es que intentes implementar todo lo que hemos hecho en este tutorial pero desde C++, eso te ayudará a alcanzar más soltura con el framework de clases del Engine.

En el próximo tutorial vamos a comenzar a darle armamento a nuestro personaje y ha poner más acción en nuestro juego. Puedes estar al tanto siguiéndome en Twitter (@nan2cc) . . . mientras, me encantaría escuchar tus comentarios y si tienes algún tema específico del que quisieras un tutorial también déjame un comentario, haré todo lo posible por complacerte 😉 . . . hasta la próxima, bye !!