Anda di halaman 1dari 263

Serie de tutoriales en espaol sobre Unreal Engine 4

Hola,
Los invito a una serie de tutoriales sobre el desarrollo de juegos en Unreal Engine 4.
1 - Introduccin al desarrollo de video juegos con Unreal Engine 4
Este primer tutorial pretende dar una introduccin al Unreal Engine 4. Crearemos la
base de nuestro juego, donde tendrs al personaje protagnico caminando por el nivel
usando una cmara fija, con controles bsicos. Este simple inicio nos permitir aprender
a importar los modelos 3D al proyecto. Crear la clase necesaria para controlar al
personaje. Entender la filosofa que sigue el framework de Unreal en su modelo de
clases. Una introduccin a la programacin en Unreal Engine usando C++. La
comunicacin entre C++ y el Editor. Los mecanismos de animacin del personaje y una
introduccin al Visual Scripting usando el Blueprint Editor.
2 - Tutorial: Como hacer un juego side-scroller 3D con Unreal Engine 4
En este segundo tutorial vamos a configurar la cmara del juego para lograr una vista
side-scroller. Vamos a agregar unas monedas al escenario y usar un mecanismo simple
de colisin para que el personaje las pueda recolectar, y veremos como debuguear las
colisiones en nuestro nivel. Vamos a ensearle a nuestro personaje a correr y saltar .
Veremos varios macros de variables y funciones de clase para la integracin entre el
cdigo C++ y el Editor . . . y muchas cosas ms. No te lo pierdas !!
3 - Introduccin a la Inteligencia Artificial en Unreal Engine 4
En este tutorial vamos a agregar un enemigo que estar patrullando una zona del nivel.
Cuando nos acerquemos a esa zona y el enemigo se de cuenta que estamos cerca, nos
perseguir, y si pierde nuestro rastro, volver a su tarea de vigilante. Con este simple
ejemplo veremos varios conceptos relacionados con la inteligencia artificial en Unreal
Engine 4 como el Behavior Tree, Decorators, Task, Services, BlackBoard, AIController
etc.
4 - Introduccin a la IA en UE4 parte 2 (la variante en C++)
En este tutorial no vamos a implementar ninguna funcionalidad nueva en nuestro juego.
Vamos a implementar las mismas acciones que tiene el NPC del tutorial pasado, pero en
C++. Esto nos va a servir para acercarnos un poco ms al Framework C++ que nos
brinda el Engine. Veremos como incluir nuevos mdulos al proyecto. Cmo iterar por
objetos del nivel. Cmo manipular la informacin guardada en el Blackboard que usa el
AIController desde C++ y cmo crear Task y Services para el Behavior Tree totalmente
desde C++.
5 - Cmo causar dao a un personaje con puetazos en UE4 Parte 1
En este tutorial vamos a ensearle a nuestro personaje sus primeras habilidades para
defenderse. Vamos a ensearle a dar puetazos. Esto nos servir para hacer una

introduccin al Animation Montage, al Animation Composite, a los mecanismo de


colisin que nos brinda UE4, a los mtodos para causar dao a los Pawn, a reproducir
efectos de sonido y muchas cosas ms. Lo dividiremos en dos partes por su extensin,
aqu vamos con la primera.
6 - Cmo causar dao a un personaje en UE4 Parte 2
En este tutorial vamos a golpear a otro personaje causndole dao hasta que su salud
llegue a 0 y muera. Este simple ejemplo nos permitir ver varias cosas nuevas:
- Introduccin a los mecanismo de colisin que nos brinda UE4
- El uso del MarketPlace.
- El uso del Construction Script en los blueprints
- Cmo aplicar dao a un personaje
- Introduccin al trabajo con efectos de sonido en Unreal Engine 4
- Cmo reproducir un AnimSequence directamente desde cdigo
- Como eliminar un Actor del nivel cuando ya no se va a usar ms
7 - Implementando un inventario y usando un arma en UE4
En este tutorial crearemos un sistema de inventario para equipar armas e
implementaremos la lgica para poder recoger, recargar, disparar el arma y detectar con
qu colisiona el disparo. Esto nos permitir ver varios conceptos y tcnicas nuevas para
nuestro juego. En este tutorial veremos:
- Introduccin a los Sockets, el mecanismo que nos brinda UE4 para anclar un elemento
a otro en un punto determinado.
- Uso del AnimMontage para las animaciones al usar el arma.
- Uso del LineTrace para detectar colisin con una lnea imaginaria. Con el uso de este
mtodo simularemos la trayectoria del disparo.
- Implementaremos un sistema de inventario genrico para nuestro juego, donde el
personaje podr seleccionar, de las armas que tenga disponible, cul usar.
- Agregaremos los efectos de sonido al disparar y recargar el arma.
- Veremos una introduccin a los AnimNotifies para lanzar eventos en puntos exactos de
una animacin.
- Y muchas cosas ms, as que no te lo pierdas.
8 - Implementando un AI Character con un arma en UE4/
En este tutorial vamos a unir muchas de las cosas que ya hemos visto en tutoriales
anteriores para agregar un enemigo a nuestro juego. Este enemigo estar patrullando
una zona del nivel con un arma, al acercarnos, comenzar a dispararnos hasta matarnos.
De igual forma, ya con el arma que configuramos para nuestro personaje en el tutorial
pasado, podremos defendernos de estos ataques.
9 - Introduccin al uso de Delegates y Event Dispatchers en Unreal Engine 4
En el desarrollo de videojuegos algo que necesitamos muy a menudo es notificar a los
distintos elementos del juego cuando ocurre algn evento, por ejemplo, cuando un

personaje muere, cuando las fuerzas enemigas comienzan a atacar nuestra base, cuando
alcanzamos un objetivo determinado del juego . . . en fin, en muchsimos casos. Es
precisamente en estas situaciones donde nos vienen a ser de gran ayuda los Delegates.
Espero que te sea til y te guste, si es as, djame saber tus comentarios y comprtelo
con el resto de tus amigos tambin apasionados por el desarrollo de video juegos con
Unreal Engine 4. Puedes seguirme en Twitter (@nan2cc), para que estes al tanto de los
proximos tutoriales.
Saludos

Introduccin al desarrollo de video


juegos con Unreal Engine 4
2014/09/21 por nan2cc 11 comentarios
Unreal Engine 4, en mi opinin, es uno de los motores de juegos ms potente que existe
en la actualidad, y el equipo de Epic Games lo ha puesto por completo a disposicin de
todos bajo una licencia 19 USD mensuales.
Este primer tutorial pretende dar una introduccin al UE4. Crearemos la base de nuestro
juego, donde tendrs al personaje protagnico caminando por el nivel usando una
cmara fija, con controles bsicos. Este simple inicio nos permitir aprender a importar
los modelos 3D al proyecto. Crear la clase necesaria para controlar al personaje.
Entender la filosofa que sigue el framework de Unreal en su modelo de clases. Una
introduccin a la programacin en Unreal Engine usando C++. La comunicacin entre
C++ y el Editor. Los mecanismos de animacin del personaje y una introduccin al
Visual Scripting usando el Blueprint Editor.
Obteniendo el Unreal Engine 4
El proceso para obtener el motor es sper simple. Entra en
https://www.unrealengine.com/register regstrate y paga los primeros 19 USD, creme,
probablemente estos sean los 19 USD que ms alegra te darn en la vida :). Ahora
tendrs acceso a lo mismo con lo que trabaja el equipo de Epic Games.
El prximo paso es obtener el motor. Este lo podemos tener de dos formas, directo el
ejecutable desde el Launcher que al abrirlo nos dar para bajar la ltima versin o
compilando todo el cdigo fuente sip, as mismo, por si fuera poco, tenemos acceso
ha todo el cdigo fuente del motor.
En el sitio se describen bien los pasos para bajar los fuentes desde
https://github.com/EpicGames/UnrealEngine/releases y los pasos para compilarlo as
que nos detendremos aqu. De todas formas si tienes algn problema con el proceso
puedes dejarme tus comentarios.

Requisitos antes de comenzar


Es vlido aclarar en este momento que este y los prximos tutoriales asumen que tienes
un dominio AVANZADO de C++ y del desarrollo de juegos.
Modelo 3D del personaje protagnico y sus animaciones
Lo primero que necesitamos para comenzar nuestro juego es el modelo 3D del
personaje principal con sus animaciones. Todos los modelo 3D que conforman un juego,
tanto los personajes como los objetos y las animaciones son creados por los diseadores
y animadores de nuestro equipo, con herramientas de modelado y animacin 3D como
Maya, 3DsMax o Blender. Al terminar el proceso de modelacin y animacin en estas
herramientas, se exporta el modelo, el esqueleto y las animaciones en formato FBX.
Como en lo personal, el modelado y la animacin 3D se me da muy mal :) vamos a
partir de los recursos en FBX de uno de los proyectos de ejemplo que viene con el UE4.
Esto es exactamente lo que nos dara nuestro equipo de diseo. Puedes bajar los
recursos aqu: https://d26ilriwvtzlb.cloudfront.net/a/a7/ThirdPerson_FBX.zip
Descomprime el .zip, de momento solo trabajaremos con HeroTPP.FBX, Walk.FBX y
Idle.FBX. Si tienes algn software de modelado 3D, como Maya por ejemplo, puedes
importar estos ficheros para que les des un vistazo de cerca.

Archivo Hero.FBX cargado en Maya 2015. Vista del esqueleto.

Archivo Hero.FBX cargado en Maya 2015. Vista del modelo.

Hero.FBX es el modelo 3D de nuestro personaje con su esqueleto para poderlo animar.


Idle.FBX y Walk.FBX son las animaciones de reposo y caminar del personaje. En estos
dos ltimos archivos no se encuentra el modelo ya que no es necesario, para las
animaciones solamente necesitamos la informacin del movimiento de los huesos del
esqueleto, por lo que al exportar las animaciones no hay que incluir el modelo.
Creando un nuevo proyecto en Unreal Engine 4
Ya con nuestro modelo 3D y sus animaciones en formato FBX estamos listo para
comenzar. Lo primero es crear el proyecto. Crear un nuevo proyecto en Unreal Engine
es sper simple. Abrimos el editor y nos muestra una ventana con dos pestaas: Project,
que contiene los proyectos existentes previamente creados y New Project, que como es
lgico, nos permite crear un nuevo proyecto.
Una de las primeras cosas geniales que encontramos al intentar crear un proyecto nuevo,
es que ya el UE4 viene con un grupo de Proyectos Plantilla que podemos usar como
base de nuestro juego, segn el estilo que queramos crear. 3ra Persona, 1ra Persona,
Top-Down o Side-Scroller.
Como el objetivo que tiene este primer tutorial, es una introduccin al UE4, no vamos a
usar ninguna de estas plantillas relativamente avanzadas, vamos a crear nuestro
proyecto prcticamente desde cero, usaremos el Template Basic. Selecciona New
Project/Basic Code y abajo en el campo nombre escribimos el nombre de nuestro
proyecto, en este caso yo usar UE4Demo. Por ltimo da clic en Create Project.

Ventana para Crear o Abrir un proyecto en Unreal Engine 4


Hecho esto se crea automticamente el proyecto y se abre en el IDE correspondiente
segn el sistema que usemos. Para Windows es Visual Studio 2013 y para MAC OS es
XCode 5.1. Este tutorial es desarrollado en MAC OS, por lo que estoy usando como
IDE de programacin el XCode. Una vez abierto el XCode con el proyecto, tenemos
que compilarlo para poderlo abrir en el Editor. Da clic en la esquina superior izquierda
para seleccionar el Scheme UE4DemoEditor Mac y despus Men Product/Build
For/Running.
El proceso de compilacin demorar unos segundos. Una vez que termina podemos
seleccionar desde el men del XCode, Product/Run. Esto nos abrir automticamente el
Editor con nuestro proyecto.

Unreal Engine 4 Editor con nuestro nuevo proyecto acabado de abrir


UE4 nos crea una escena con algunos objetos agregados a la misma. De momento
vamos a dejarlo. Puedes dar clic en el botn Play de la barra Superior (Toolbar) para ver
lo que tenemos. Por defecto tendremos el control de la cmara con el mouse y el teclado
y podremos desplazarnos por la escena, pero por supuesto, este no es el objetivo,
nosotros queremos que entre en este mundo nuestro personaje :)
Importando modelo 3D de nuestro personaje
Ya nuestro equipo de diseo nos entreg el modelo exportado en FBX con su esqueleto
y su dos animaciones bsicas :), ahora vamos a importarlo en el proyecto. En el Panel de
la esquina inferior izquierda del Editor tendemos el Content Browser. En este panel es
donde tendremos organizados todos los recursos de nuestro juego. Da clic en el Botn
New y selecciona New Folder y dale un nombre a la carpeta, por ejemplo Character.
Hecho esto tendremos una nueva carpeta en el Content Browser, entra en ella,
selecciona Import y busca el FBX del personaje: Hero.FBX (los FBX de las
animaciones los vamos a importar ms tarde). Recuerda que en este FBX lo que
tenemos es el modelo 3D del personaje con su esqueleto. Al dar en OK nos sale la
ventana FBX Import de UE4 y ya automticamente seleccionado Skeletal Mesh.

Ventana FBX Import del Unreal Engine 4


Vamos a tomarnos unos minutos para un poco de teora. Como puedes ver en esta
ventana de import se muestran tres tipos de recursos que se pueden importar desde
FBX. Static Mesh, Skeletal Mesh y Animation.
Static Mesh: Un Static Mesh es un objeto esttico de nuestro juego, por ejemplo una
silla, un edificio. O sea, solamente el modelo 3D sin animacin, sin esqueleto.
Skeletal Mesh: Un Skeletal Mesh, es exactamente lo que estamos importando ahora, un
modelo 3D con un esqueleto asociado para ser animado. O sea, todos los personajes de
nuestro juego seran Skeletal Mesh.
Animation: Un Animation, es la informacin de transformaciones de los huesos de un
esqueleto para darle vida a las acciones como caminar, saltar, etc. Lo que tenemos en
Idle.FBX y Walk.FBX que importaremos ms adelante.
Automticamente UE4 detecta que lo que estamos importando es un Skeletal Mesh no
es necesario cambiar ms nada, los parmetros por defecto son suficiente, da clic en el
botn Import. En caso de algn warning en el proceso de importacin, ignralo. En
prximos tutoriales veremos todo el proceso de Exportar/Importar y el Animation
Rigging Toolset que nos da Epic para preparar los modelos y las animaciones y
abordaremos en detalles este tema.
Una vez importado el modelo en el Content Browser tendremos 3 nuevos elementos:
Hero (SkeletalMesh), Hero_PhysicsAsset (PhysicsAsset) y Hero_Skeleton (Skeleton).
Si haces doble clic en el SkeletalMesh puedes abrir el modelo importado en el Editor
Persona de UE4. Persona es el editor de Skeleton, Skeletal Meshes, Animations
Blueprints y otros elementos de animacin en UE4.

El Skeletal Mesh de nuestro hroe en el Persona Editor


Al abrir el SkeletalMesh en Persona a la izquierda tendremos el Skeleton Tree que es el
rbol con todos los huesos que conforman el esqueleto del modelo. En el panel de abajo
tenemos el Mesh Details. Este panel est compuesto por varias secciones, con los
Materiales aplicados al modelo (De momento no tenemos ningn material, o mejor
dicho, solamente tenemos un material por default que le da esa vista gris opaca a
nuestro personaje)
El Hero_PhysicsAsset es el PhysicsAsset que se genera automticamente al importar el
Skeletal Mesh, este asset de momento no lo usaremos, en prximos tutoriales veremos
para que es, pero si eres muy curioso dale doble clic, te abrir el editor que trae UE4
para manipular este tipo de assets. En la esquina superior izquierda tiene un botn que
dice Simulate, da clic en l y mira lo que pasa. Eso te dar una nocin del objetivo de
este recurso generado automticamente al importar el Skeletal Mesh.
Por ltimo el Hero_Skeleton es solamente el esqueleto del modelo que importamos,
pero el esqueleto por separado. Una caracterstica genial de UE4 es que podemos
compartir el mismo esqueleto entre distintos modelos 3D que sean relativamente
parecidos en su modelo. En vez de tener que importar siempre para cada uno de estos el
modelo 3D y el esqueleto, solamente importamos el esqueleto una vez, y podemos
asociar distintos modelos a este esqueleto.
Bien, ya tenemos en nuestro proyecto los recursos del personaje principal, vamos ahora
a lo que nos gusta, el cdigo :)
Introduccin a la programacin en Unreal Engine 4

Un proyecto en Unreal Engine 4 est compuesto bsicamente de dos grandes piezas que
trabajan en conjunto. Los niveles, que es lo que se trabaja en el Editor y el proyecto de
programacin, que trabajamos en el IDE de programacin. Vimos como al crear un
nuevo proyecto en UE4 se crean ambas partes. Ahora vamos a trabajar en la segunda
parte, la parte del cdigo.
En Unreal Engine 4 se programa en C++, al crear un nuevo proyecto, automticamente
se crea un proyecto en el XCode (o Visual Studio si usas Windows) con las clases
bsicas para nuestro juego. Abre tu IDE de programacin con el proyecto creado.
Dentro de la carpeta Source es que se encuentran los fuentes nuestros. Dentro de la
carpeta Engine estn todos el framework. Tener acceso a esto es genial, porque sirve de
mucha ayuda para revisar como estn implementadas las clases, o para que es una
determinada propiedad, viendo los comentarios puestos por el propio equipo de Epic.
Antes de crear nuestra primera clase vamos a comentar rpidamente la filosofa que
sigue Unreal Engine en su framework.
En UE4 todos los elementos que aparecen en nuestro juego son Actors (heredan de la
clase AActor). Una silla, una mesa, un enemigo o el personaje principal. Los elementos
del juego que son controlados, o sea que no son estticos, que tienen un
comportamiento, son Pawns. Hay un tipo especial de Pawn que es el Character. El
Character es el Pawn que representa al personaje principal y tiene implementaciones
particulares que solo tendr el Pawn que ser controlado por el jugador. Por ejemplo, si
en nuestro juego tenemos al personaje principal y a un enemigo. El personaje principal
ser un Character y el enemigo ser un Pawn solamente. Ahora todos los Pawns son
controlados por una clase Controller, para el caso del Character, este es controlado por
un PlayerController. El PlayerController es la clase que recibe las entradas del jugador,
del ser humano, y mediante ellas controla al personaje en el juego, al Character.
Bsicamente el PlayerController representa al ser humano, el Character (Tipo especial
de Pawn) representa al personaje dentro del juego y es controlado por el
PlayerController. Mientras que los otros Pawns pueden ser controlados, por ejemplo,
por AIController.
. . . sip :S, bastante enredado, pero poco a poco a medida que te familiarices con Unreal
Engine dominars esta filosofa, la jerarqua de clases y la relacin entre ellas.
Volviendo al cdigo, dentro de la carpeta Source tenemos una carpeta con el nombre
que le dimos al proyecto, en mi caso UE4Demo y dentro unas pocas clases con las que
comenzar nuestro juego.
La primera clase a tener en cuenta es UE4DemoGameMode esta es la clase que define
el GameMode de nuestro juego. En Unreal la clase GameMode define las reglas del
juego, por ejemplo, las condiciones en las que se gana, las condiciones en las que se
pierde etc, adems es la encargada de definir el PlayerController, el Pawn por defecto,
entre otras muchas cosas. Es el ncleo del juego. Si abrimos el .h veremos que es una
clase que hereda de AGameMode y de momento no tiene ms nada.
1
2
3
4

//AUE4DemoGameMode.h
#pragma once
#include "GameFramework/GameMode.h"
#include "UE4DemoGameMode.generated.h"

5
6
7
8
9
10
11

UCLASS()
class AUE4DemoGameMode : public AGameMode
{
GENERATED_UCLASS_BODY()
};

Como notars de seguro, la clase tiene en su declaracin dos macros que te llamarn la
atencin, UCLASS() y GENERATED_UCLASS_BODY
Unreal Engine posee un robusto sistema para el manejo de objetos. La clase base para
los objetos en Unreal es UObject. el macro CLASS puede ser usado en clases que
derivan de UObject, de esta forma el sistema manejador de UObjects es avisado de la
existencia de esta clase.
Al incluir estos macros logramos que la clase a bajo nivel sea tratada por los
mecanismos de Unreal como el Recolector de basura, Serializacin, Inicializacin
automtica de las propiedades, Integracin automtica con el Editor etc.
Ahora vamos a ver la implementacin de nuestro GameMode. Como vers en el
UE4DemoGameMode.cpp tendrs solamente la implementacin del constructor.
1
2
3
4
5
6
7
8
9
1
0

//AUE4DemoGameMode.cpp
#include "UE4Demo.h"
#include "UE4DemoGameMode.h"
#include "UE4DemoPlayerController.h"
AUE4DemoGameMode::AUE4DemoGameMode(const class
FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
PlayerControllerClass = AUE4DemoPlayerController::StaticClass();
}

El constructor del GameMode de nuestro juego de momento solamente tiene la


inicializacin del atributo PlayerControllerClass. PlayerControllerClass es el
PlayerController para nuestro juego, o sea, la clase que ser la interfaz entre el ser
humano y el Character que este controlar. Aqu simplemente es inicializada con una
instancia esttica de nuestro UE4DemoPlayerController. Por eso es que podemos
movernos como un fantasma por todo el nivel cuando corremos el proyecto ahora
mismo. Tenemos un PlayerController, pero como no tenemos un Character no tenemos
cuerpo dentro del juego.
La otra clase que tenemos ya previamente creada es UE4DemoPlayerController. Esta es
la implementacin del PlayerController de nuestro juego y como vers est vaca, de
momento no necesitamos nada personalizado en ella, todo lo necesario para nuestro
PlayerController de momento est en la clase base APlayerController, pero dejamos esta
clase por aqu para cuando necesitemos implementar algn comportamiento
personalizado.

Bien, basta de teora, vamos a la practica.


Ya tenemos importado en el Editor los recursos que conforman a nuestro personaje,
pues vamos a acabar de hacerlo entrar en escena :)
Creando nuestra primera clase en Unreal Engine
Como lo primero que vamos a hacer es darle vida a nuestro personaje, la clase que
vamos a crear es la clase del personaje. Como comentamos anteriormente, el personaje
controlado por el jugador es un Pawn, pero es un Pawn especial, es un Character. Por lo
que la clase que controle al personaje protagnico de nuestro juego tiene que heredar de
Character.
Para agregar una nueva clase al proyecto la forma ms cmoda de hacerlo es desde el
Editor. Vuelve al Editor y mediante el men principal selecciona File/Add Code to
Project. Tendremos una ventana para seleccionar la clase base de la nueva clase que
como dijimos ser Character. En esa ventana puedes ver las otras clases bases comunes
en Unreal Engine y una pequea descripcin de las mismas. Selecciona Character, da en
el botn Next, escribe el nombre para tu clase, por ejemplo, HeroCharacter y finaliza el
proceso. Al finalizar el Editor te pregunta si quieres abrir la clase en el IDE, le damos
OK y ya veremos ah nuestra clase HeroCharacter creada. La estructura de momento ya
es conocida, una clase C++ normal que hereda de ACharacter y con los macros ya
explicados UCLASS() y GENERATED_UCLASS_BODY().
Configurando el Character desde el Blueprint Editor.
Ya tenemos nuestra clase para representar el personaje protagnico de nuestro juego,
este es un buen punto para comentar una de las cosas que en lo personal ms trabajo me
cost adaptarme al entrar en el mundo de Unreal Engine, sobre todo porque llegu a
Unreal Engine despus de trabajar mucho en el desarrollo de juegos 2D con motores
como el Cocos2D. En este caso todo se hace desde cdigo (aunque ya a estas alturas
han varios Editores geniales para Cocos2D). En UE4 la filosofa de trabajo es muy
distinta, aqu por supuesto que podemos hacerlo todo desde programacin pero esto
implica que el ritmo de produccin generalmente ser ms lento y propenso a bug. Por
este motivo al desarrollar juegos sobre Unreal Engine trabajaremos indistintamente con
el Editor o directamente desde el cdigo. Bsicamente es decisin de los desarrolladores
cuando usar uno u otro.
Para demostrar el engranaje entre el cdigo en C++ y el Editor en Unreal Engine vamos
a configurar nuestro Character en los dos lados, esto tambin nos permitir demostrar lo
genial que quedan comunicados el cdigo C++ y el Editor.
Bien, ya tenemos desde cdigo nuestra clase para representar al Character, vamos ahora
a configurar los componentes del Character pero desde el Editor. Abre el Editor y en el
Toolbar tenemos el botn Blueprints. Selecciona Blueprints/New Class Blueprint en la
parte de abajo de la ventana hay una seccin que dice Custom Classes, selecciona ah y
busca la clase que acabamos de crear para nuestro Character, HeroCharacter, y le
ponemos un nombre, por ejemplo, HeroCharacterBlueprint y selecciona para que se
cree dentro de la carpeta Game/Character. Una vez terminado el proceso se abrir el

Blueprint Editor en el modo Components. Desde aqu podemos configurar todo nuestro
Character.

A la izquierda del editor tenemos el panel Components este panel contiene todos los
componentes que conforman el Character al seleccionar uno, en el panel de abajo se
muestran las propiedades de ese componente. El CharacterMovements como el nombre
lo indica es el componente que contiene las propiedades que afectan el movimiento del
Character, por ejemplo, aqu tenemos Max Walk Speed que es el mximo de velocidad
que toma el personaje al desplazarse, hay muchsimas ms propiedades, dale un vistazo
a todas por arriba para que tengas una idea de todo lo que se puede configurar en el
Character con respecto al movimiento.
El otro componente que tiene un Character es el CapsuleComponent. El
CapsuleComponent es usado para la deteccin de colisiones con el personaje. Es esa
capsula transparente que se ve en el Viewport del Editor y es la zona de colisin del
personaje.
Por ltimo dentro del CapsuleComponent tenemos un Mesh, que como ya te imaginars
es el Mesh que representa a nuestro personaje. Adems hay un ArrowComponent que
nos ayuda para saber la direccin del Character.
Bien, el primer paso ser acabar de configurar el Mesh de nuestro Character. Selecciona
en el panel de Componentes el componente Mesh y en el panel detalles en la seccin
Mesh tienes la propiedad Skeletal Mesh despliega el combobox que hay aqu y
selecciona el nico Skeletal Mesh que tenemos en nuestro proyecto que creamos al
importar el fbx de nuestro hroe. Al hacer esto en el Viewport se ver el modelo de
nuestro hroe. Usa las herramientas de traslacin y rotacin para colocar el Mesh dentro
del CapsuleComponent y mirando en la misma direccin que el Arrow Component. Por
ltimo da clic en el botn Save en la esquina superior derecha del Editor.

Mesh del personaje en la posicin correcta en el HeroCharacterBlueprint


Hecho esto acabamos de darle un cuerpo a nuestro Character. Vamos a probar. Cierra el
Editor del Character y corre el juego a ver que tenemos.
:( como notars no hay ningn cambio, seguimos teniendo control gracias al
PlayerController por defecto pero no tenemos nuestro personaje ni nada. Bien, el
problema es que nos faltaron algunas cosillas.
Primero, asegrate que tienes configurado bien el GameMode. Da clic en el botn
World Settings del Toolbar y asegrate tener seleccionado en la seccin GameMode
nuestra clase U4DemoGameMode, debajo de GameMode tendrs los elementos
configurados en este GameMode en PlayerControllerClass est nuestro PlayerController
(UE4DemoPlayerController) ya que en el constructor de la clase UE4DemoGameMode
inicializa esa propiedad, pero como notars Default Pawn Class dice Default Pawn. Ese
es exactamente el problema que tenemos. Creamos nuestro Character y le dimos un
cuerpo pero no hemos definido en el GameMode que HeroCharacter es el Character (el
Default Pawn Class ) de nuestro juego.
Vamos ha hacer esto desde el cdigo para demostrar nuevamente la comunicacin entre
los componentes del Editor y el cdigo en C++. Cierra el Editor abre el proyecto C++ y
busca la clase UE4DemoGameMode modifica la implementacin del constructor para
que quede de la siguiente forma.
1 AUE4DemoGameMode::AUE4DemoGameMode(const class
2 FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
3{
4
PlayerControllerClass = AUE4DemoPlayerController::StaticClass();
5
//Obtiene en PlayerPawnBPClass.Object la referencia al

6
7
8 HeroCharacterBlueprint creado y configurado desde el Editor
static ConstructorHelpers::FObjectFinder<UClass>
9 PlayerPawnBPClass(TEXT("Class'/Game/Character/HeroCharacterBlueprint.
1 HeroCharacterBlueprint_C'"));
0
1
//Inicializa el atributo DefaultPawnClass con el
1 HeroCharacterBlueprint creado y configurado desde el editor
if (PlayerPawnBPClass.Object != NULL)
1
{
2
DefaultPawnClass = PlayerPawnBPClass.Object;
1
}
3}
1
4
Vamos a dar un stop aqu para explicar que acabamos de hacer con estas pocas lneas
porque aunque tengas experiencia en C++ de seguro que esta sintaxis te parecer algo
rara. En la primera lnea lo que hacemos es buscar y obtener la instancia de la clase
HeroCharacter creada en el editor mediante el Blueprint Editor. Creamos una variable
del tipo FObjectFinder, FObjectFinder es una estructura parametrizada publica que se
encuentra dentro de otra estructura de nombre ConstructorHelpers. FObjectFinder
recibe en su constructor la direccin del objeto que vamos a instanciar, si el objeto es
encontrado satisfactoriamente su instancia se almacena en la propiedad Object.
Un buen consejo, como tenemos los fuentes del Framework, puedes ver la
implementacin de todas estas estructuras ConstructorHelpers, FObjectFinder. En
XCode basta con dar clic sobre su nombre con la tecla cmd presionada. Esto te llevar a
la declaracin de la estructura. Tomate unos minutos y dale un vistazo por arriba para
que entiendas mejor su funcionamiento. Por ltimo notar que para definirle la ruta a
FObjectFinder usamos el Macro TEXT, bsicamente todos los strings que escribamos
directo en el cdigo lo tendemos que hacer con esto, para que el compilador pueda
convertir el string al tipo de dato correcto, en este caso un TCHAR *.
Bien, pues en teora tenemos en PlayerPawnBPClass.Object la instancia de nuestro
Character (PlayerPawnBPClass es el nombre que le dimos a la variable que acabamos
de crear de tipo FObjectFinder), lo que queda es inicializar la propiedad
DefaultPawnClass con este objeto. La clase GameMode tiene la propiedad
DefaultPawnClass que define el Pawn que usar el personaje.
Listo, compila y ejecuta el juego. Al arrancar el juego automticamente se agrega al
Level nuestro personaje. Esto es porque en el Level que nos crea el Unreal Editor por
defecto con la plantilla que seleccionamos al crear el proyecto, tiene un Actor de tipo
Player Start. Y el GameMode automticamente busca en el Level si hay una instancia de
un Player Start y agrega en esa posicin el Character.
Pero que problema tenemos ahora, perdimos el control, ya no podemos desplazarnos por
la escena y la cmara est como en los ojos del personaje :(. Bien, vamos a solucionar
este asunto configurando temporalmente una cmara esttica en nuestro juego.
Configurando una cmara esttica desde C++

En el Editor da clic derecho dentro del ViewPort y selecciona del men desplegable
Place Actor/Camera. Usa las herramientas de traslacin y transformacin para apuntar la
cmara en la direccin del Play Start, para que se vea el personaje. As me qued a mi:

Ahora vamos a decirle al Unreal que la vista del juego ser desde esta cmara. Para esto
tenemos que comentar algo de teora.
Como hablamos anteriormente segn la filosofa de Unreal es el PlayerController la
interfaz entre el personaje protagnico del juego (el Character) y el ser humano. Por lo
que es lgico que lo referente a la vista del juego sea implementado aqu.
PlayerController tiene el mtodo SetViewTargetWithBlend este mtodo permite definir
en cualquier momento a donde es que est mirando la cmara del juego. Lo que
vamos a hacer es llamar a este mtodo y decirle que use la cmara que pusimos en el
Level como la cmara del juego.
Podemos cambiar la direccin a la que apunta la cmara de nuestro juego en cualquier
momento, pero en este caso queremos que desde el inicio sea la direccin a la que
apunta la cmara que agregamos al level. Para esto vamos a usar un evento muy usado
en Unreal que es el evento BeginPlay. todas las clases que hereden de AActor tienen
este mtodo que se llama, como dice su nombre, cuando inicia el juego. Vamos a
sobrescribir este mtodo en nuestro PlayerController (que deriva de AActor) para en ese
momento cambiar la cmara del juego.
Abre UE4DemoPlayerController.h y abajo del macro
GENERATED_UCLASS_BODY() agrega la siguiente lnea: virtual void BeginPlay()
override; con esto hacemos visible el mtodo BeginPlay en nuestra clase
UE4DemoPlayerController para poderlo sobrescribir en el .cpp.

Abre ahora UE4DemoPlayerController.cpp y agrega el siguiente mtodo debajo del


contructor. Revisa con detenimiento los comentarios para que entiendas lo que se hace
dentro del mtodo.
1
2
3 /** Metodo heredado de la clase AActor se llama automaticamente por
4 el motor cuando comienza el juego. */
void AUE4DemoPlayerController::BeginPlay()
5 {
6
//Llamamos el Begin Play de la clase padre
7
Super::BeginPlay();
8
//Recorremos todos los Actores en el Level mediante el
9
TActorIterator
1
//TActorIterator es un iterator parametrizado que nos permite
0 recorrer todos los actores en el level
11
for (TActorIterator<ACameraActor> It(GetWorld()); It; ++It)
{
1
//Obtenemos el actor actualmente en el loop. Como solo
2
tenemos un solo ACameraActor en el Level, el iterator solo iterar
1 una vez
3
ACameraActor* _mainCamera = *It;
1
4
//Configuramos el nuevo punto de vista del juego con la
1 camara.
//SetViewTargetWithBlend puede recibir ms parametros, pero
5
tienen valores por defecto, y de momento no necesitamos
1 modificarlos.
6
this->SetViewTargetWithBlend(_mainCamera);
1
}
7 }
1
8
Listo !! compila y corre. Ahora vers el juego usando la cmara que agregamos al Level
y ya podrs ver nuestro Character agregado a la escena.
Configurando una cmara esttica mediante el Blueprint Editor
Bien, quisiera hacer un parntesis aqu para volver a tocar el tema del Blueprint Editor.
Al comenzar en Unreal Engine muchos chocamos con la incgnita: Cmo hago esto?
Mediante C+ o mediante el Blueprint. Al final la decisin es de cada cual y a medida
que vayas cogiendo soltura en Unreal Engine sabrs al directo si lo que vas a hacer en
C++ o en el Blueprint Editor. Quiero aprovechar este momento para demostrar esto.
Vamos a hacer lo mismo que acabamos de implementar en C++, o sea, cambiar la
cmara del juego, pero ahora sin escribir una lnea de cdigo, todo lo haremos mediante
el Blueprint Editor.
En el Editor da clic en el botn Blueprint del Toolbar y selecciona Open Level Blueprint
esto te abrir el Blueprint Editor con el archivo Blueprint para el Level completo.
Digamos que es en este Blueprint donde implementaremos las cosas generales del nivel.

Siguiendo la lgica que usamos para implementar esto desde C++. Lo primero que
hicimos fue implementar el Evento BeginPlay. Pues eso mismo haremos aqu, el
Blueprint Editor es un Editor de scripting visual, por lo que en este Editor lo que
haremos bsicamente es programar pero con grficos (si si . . . bien complejo de
asimilar y entender la primera vez :) ) aqu podemos agregar variables, eventos del
sistema, funciones de clases especificas etc. En fin, todo, o casi todo lo que haces en C+
+ lo podrs hacer en el Blueprint Editor.
Comenzaremos agregando el Evento Begin Play. Clic derecho en el centro de la pantalla
desmarca la opcin Context Sensitive y busca Event Begin Play. Acabamos de agregar a
nuestro script visual un Nodo que representa al mtodo Begin Play de nuestro juego.
Ahora, segn nuestra implementacin en C++ lo que hicimos dentro del BeginPlay fue
obtener la referencia de la cmara que tenemos en el Level y llamar al mtodo de la
clase PlayerController SetViewTargetWithBlend pasndole como parmetro la cmara.
Pues eso mismo haremos aqu.
Primero, necesitamos una referencia al PlayerController, recuerda que este script es
global a nivel del Level y la implementacin de C++ la hicimos dentro del
PlayerController.
Agrega un nuevo Nodo como ya sabes pero ahora ser Get Player Controller. Este nodo
nos retorna la referencia del Player Controller del juego. Ahora necesitamos llamar al
mtodo SetViewTargetWithBlend como mismo hicimos en C++. De nuevo agrega un
nuevo Nodo de nombre SetViewTargetWithBlend. Listo, ya tenemos todos los
elementos que necesitamos para nuestro algoritmo visual. Pero falta una cosa,
conectarlos.
El Nodo Event Begin Play tiene como un puerto que representa la salida. O sea, lo que
se va a ejecutar cuando se lance este evento en el juego y si te fijas en el nodo Set View
target with Blend tiene un puerto de entrada y de salida. El de entrada es el que nos
interesa. Da clic en el puerto del evento Event Begin Play y arrastras la flecha hasta el
puerto de entrada de Set View Target with Blend, cuando te muestre una marquita verde
sultalo. Con esto hemos hecho la conexin entre la salida de Event Begin Play y Set
View target with Blend. Que quiere decir esto, que cuando se ejecute nuestro juego, se
va a disparar el evento BeginPlay y se llamar al mtodo Set View target with Blend.
Pero que pasa, SetViewtargetWithBlend vimos que es un mtodo que pertenece al
PlayerController, por lo que hay que definirle al nodo Set View Target With Blend quien
es el Player Controller. El Nodo Get Player Controller tiene un puerto de salida que dice
Return Value y el Nodo Set View Target with Blend tiene un puerto de entrada que dice
Target. Conecta estos dos puertos y de esta forma estars diciendo que el mtodo
SetViewTargetWithBlend que se llamar es el del PlayerController retornado por el
Nodo Get Player Controller. Por ltimo recuerda que hay que pasarle como parmetro al
SetViewTargetWithBlend el Actor que usar para configurar el nuevo punto de mira.
Para esto nos falta agregar un ltimo Nodo, el nodo que representa a la cmara. Salva
estos cambios, cierra el Editor y selecciona en el Level la cmara que agregamos
anteriormente. Ahora abre de nuevo el Editor da clic derecho y vers que tienes un
acceso directo para agregar un Nodo Camera Actor. Una vez agregado conecta el puerto
de salida del camera actor al puerto New View Target del Set View Target with Blend.
Listo, ya tenemos nuestro script visual completo. En la esquina superior izquierda tienes
un botn que dice Compile. Da clic ah. Por ltimo vamos a eliminar la sobre-escritura

del mtodo Begin Play en la clase C++ ya no es necesario (si quieres comntalo para
que no pierdas el cdigo).
Cierra el Editor, abre el proyecto C++ y comenta en el UE4DemoPlayerController.h la
declaracin del mtodo BeginPlay. Ve ahora al UE4DemoPlayerController.cpp y
comenta o elimina completamente la implementacin del mtodo BeginPlay.
Listo !!. Compila y ejecuta el juego. Como notars, es idntico el resultado :). Ya te
digo, es decisin tuya implementar lo que quieras en el Blueprint Editor o en C++ tu
mismo le iras encontrando las ventajas y desventajas a cada mtodo segn lo que
quieras hacer.
Tomate unos minutos si quieres, que an nos quedan varias cosas :)
Configurando las animaciones del personaje
De momento lo que tenemos es bastante poco funcional. Simplemente al abrir el juego
vemos al personaje protagnico, ya visto desde una cmara fija pero est ah quieto sin
hacer nada y esttico totalmente. Vamos a darle un poco de vida.
Recuerda que nuestro equipo de diseo :) nos entreg adems del modelo con su
esqueleto en FBX las animaciones de caminar y reposo, tambin en formato FBX listas
para importarlas. Pues vamos a ello. Abre el Editor en el Content Browser crea una
nueva carpeta, yo le pondr Animations. Aqu tendremos todas las animaciones que
importemos. Entra a la carpeta e importa los dos FBX Walk.FBX e Idle.FBX. Al
seleccionarlas vers que por defecto en la ventana de FBX Import sale seleccionado
Animations. Ms abajo tiene la opcin que permite ya en el momento de la importacin
seleccionar el esqueleto al que estn asociadas estas animaciones. Da clic ah y
selecciona Hero_Skeleton por ltimo da clic en Import.
Ya tenemos las animaciones de nuestro personaje, si quieres puedes darle doble clic
desde el Content Browser para abrirlas en el Persona Editor y ver un preview de las
mismas. Desde este Editor puedes ver todos los detalles de la animacin, reproducirla y
muchas ms cosas que veremos en prximos tutoriales.
Ya tenemos las animaciones ahora falta asociarlas con nuestro personaje.
Creando la maquina de estado y actualizando el Character con la animacin de
reposo y caminar mediante Animation Blueprints.
El Animation Blueprints es la herramienta que nos da Unreal Engine para implementar
toda la lgica de las animaciones del personaje de una forma sper simple. A partir de
mquinas de estado y visual scripting.
Vamos a crear entonces el Animation Blueprints para el personaje. Entra en el Content
Browser a la carpeta Animations da clic derecho en un espacio vaco y selecciona
Animation/Animation Blueprint. Esto te abrir la ventana de creacin de Animation
Blueprint. En la seccin Parent Class selecciona AnimInstance y abajo en la seccin
Target Skeleton escribe el nombre del esqueleto que usa nuestro hroe, Hero_Skeleton
por ltimo da clic en el botn OK.

Automticamente se agrega al Content Browser un AnimBlueprint con el nombre


seleccionado para que lo cambies. Ponle el nombre que prefieras, por ejemplo
HeroAnimBlueprint. Ahora, antes de hacer algo en el HeroAnimBlueprint vamos a
definirle en nuestro Character que ser este el Blueprint que usar para sus animaciones.
Para esto ve en el Content Browser a donde tienes el Blueprint del character. En mi caso
Game/Character/HeroCharacterBlueprint y dale doble clic. En la esquina superior
derecha, selecciona el Modo Defaults y vers que hay una seccin de nombre Animation
para la propiedad Animation Mode selecciona Use Animation Blueprint y para la
propiedad Anim Blueprint Generated Class selecciona la clase que acabamos de crear
HeroAnimBlueprint_C. Listo, guarda y cierra el Editor.

Ve ahora al HeroAnimBlueprint, dale doble clic y se te abrir el Persona Editor. De


inicio tienes un nodo Final Animation Pose. A este Node conectaremos la salida de lo
que vamos a crear ahora, pero primero, de nuevo un poco de teora.
En Unreal Engine hay un mecanismo sper genial e intuitivo para definir las
animaciones que tienen los personajes segn su estado y las condiciones que definen
cada estado. O sea, si el personaje est en reposo se animar la animacin de reposo, si
el personaje est caminando se ejecutar la animacin de caminando. Se pueden hacer
ligamentos entre animaciones, para que estos cambios sean mas fluidos, adems definir
las condiciones de cada estado. Por ejemplo, para que el personaje est en reposo su
atributo velocidad tiene que estar en cero, para que est caminando su atributo
velocidad ser distinto de cero, y as. Todo esto se puede hacer mediante una maquina
de estado y un script visual en el Animation Blueprint.
Vamos a crear la maquina de estado, de momento ser muy simple. Dentro del
AnimBlueprint Editor da clic derecho y selecciona StateMachine/Add State Machine
esto agrega un Nodo de tipo StateMachine a la escena. Cmbiale el nombre a algo
lgico, como HeroStateMachine o como prefieras. Ahora, dentro de ese State Machine
vamos a definir los distintos estados que tendr el personaje. Da doble clic en el nodo
State Machine para entrar a editarlo. Dentro tienes un nodo de nombre Entry, da clic
derecho Add State y ponle al nuevo nodo Idle de nombre. Ahora conecta, como
mismo hicimos en el level blueprint, el puerto de salida del nodo Entry al puerto de
entrada del nodo Idle que acabamos de crear.

Seguidamente vamos a definir la lgica del estado Idle. Dale doble clic al nodo Idle, da
clic derecho y selecciona Animation/Play Idle. Esto agrega el Nodo que representa la
animacin Idle que importamos anteriormente al Editor. ahora conecta este nodo al
nodo Final Animation Pose.
Listo vamos a repasar como quedan todas las conexiones en cada uno de los niveles. De
adentro hacia afuera tenemos nodo Play Idle conectado al nodo Final Animation Pose.
En el nivel superior (HeroStateMachine) nodo Entry conectado al nodo Idle y por
ltimo en el nivel superior (AnimGraph) el nodo HeroStateMachine conectado al nodo
Final Animation Pose. Hecho esto da clic en Compile en la esquina superior derecha del
Editor. En el panel de la izquierda podremos ver un preview ya del personaje con la
animacin del Idle

Ejecuta el juego. Ya tenemos a nuestro personaje en su estado de reposo y animndose


perfectamente.

Personaje principal ya en el juego en estado de reposo animndose correctamente.


Configurando los controles del juego
Muy bien, hasta ahora hemos creado y configurado el Character, hemos configurado
una cmara fija temporal para el juego y hemos configurado la primera animacin del
personaje, el prximo paso de seguro que sabes cual es . . . hacer caminar al chico :)
Primero vamos a definir los controles del juego. Para esto desde el Unreal Engine Editor
men Edit/Project Settings, Seccin Engine/Input, Bloque Bindings. Da clic en el botn
del + en Axis Mapping y despliega la flechita. En el campo para escribir, escribe

MoveForward. Da clic en la flechita al lado del EditText y despliega el campo y


selecciona W y en Scale deja 1.0. Da clic de nuevo en el + al lado del EditText de
MoveForward selecciona del nuevo combobox la S y en Scale pon -1.0.
Ahora da clic en el + de Axis Mappings para crear otra seccin al nivel de
MoveForward. En el nuevo EditText escribe MoveRight. Agrega dos hijos a
MoveRight: A con Scale igual a -1 y D con Scale igual a 1.

Lo que acabamos de hacer es definir los controles que tendr nuestro juego. El nombre
que le ponemos, por ejemplo, MoveForward es para conocer esta entrada desde
programacin y lo que seleccionamos en el combobox es el control que disparar esta
accin. El valor de Scale es un valor numrico que llega al mtodo desde programacin,
generalmente con -1 y 1 es suficiente para la mayora de los casos. Otra cosa a notar es
que gracias a este valor de Scale las acciones que son en una direccin y en su contraria
las registramos con el mismo identificador (MoveForward por ejemplo) y simplemente
le cambiamos el valor de Scale a 1 si es hacia delante y a -1 si es hacia atrs.
Bien, hecho esto vamos a programar en el Character la lgica para lograr el
desplazamiento por la escena con estos controles, de momento ser muy simple el
desplazamiento del personaje en la escena, pero suficiente para entender como funciona
todo. Bsicamente necesitamos dos cosas. Sobrescribir el mtodo virtual void
SetupPlayerInputComponent(class UInputComponent* InputComponent) de APawn
para registrar los mtodos que se van a llamar cada vez que se detecte las entradas que
definimos, o sea un MoveForward o un MoveRight, y por supuesto, implementar el
desplazamiento del Character en dependencia de la entrada.
Abre la clase HeroCharacter.h y modifcala para que quede de la siguiente forma:
1 UCLASS()
AHeroCharacter : public ACharacter
2 class
{
3

4
5
6
7
8
9
1
GENERATED_UCLASS_BODY()
0
11
1 protected:
2
/**
1
* Se llama cuando el motor detecta la entrada configurada para
3 'MoveForward'.
1
* En este caso cuando el usuario toca la tecla W o S del
4 teclado
*/
1
void MoveForward(float Value);
5
1
/**
6
* Se llama cuando el motor detecta la entrada configurada para
1 'MoveRight'.
* En este caso cuando el usuario toca la tecla A o D del
7
teclado
1
*/
8
void MoveRight(float Value);
1
9
/**
* Metodo de la clase APawn que permite configurar los 'binding'
2
de
los
controles
0
* Es llamado automaticamente por el Engine
2
*/
1
virtual void SetupPlayerInputComponent(class UInputComponent*
2 InputComponent) OVERRIDE;
2
2 };
3
2
4
2
5
2
6
Nada raro aqu, simplemente definimos dos mtodos en donde vamos a implementar la
lgica para cuando se detecte cada entrada y agregamos aqu tambin la declaracin del
mtodo SetupPlayerInputComponent de APawn para poderlo sobrescribirlo
Ahora pasa al HeroCharacter.cpp y modifcalo para que quede de la siguiente forma:
1 #include "UE4Demo.h"
2 #include "HeroCharacter.h"
3
4 AHeroCharacter::AHeroCharacter(const class

5 FPostConstructInitializeProperties& PCIP)
6 :{ Super(PCIP)
7
8 }
9
1 void AHeroCharacter::SetupPlayerInputComponent(class UInputComponent*
0 InputComponent)
11{
//Le dice al motor que cuando detecte las entrada de tipo
1 MoveForward que llame al metodo AHeroCharacter::MoveForward
2
InputComponent->BindAxis("MoveForward", this,
1 &AHeroCharacter::MoveForward);
3
//Le dice al motor que cuando detecte las entrada de tipo
1
MoveRight
que llame al metodo AHeroCharacter::MoveRight
4
InputComponent->BindAxis("MoveRight", this,
1 &AHeroCharacter::MoveRight);
5 }
1
6
1 /**
7 * Se llama cuando se detecta la entrada de tipo MoveForward
1 (Cuando el usuario toca las teclas W o S).
* Determina la direccin en la que est el personaje y le aplica
8 un movimiento (positivo o negativo) en esa direccin
1 *
9 * @param Value Value es igual a 1 cuando se detecta W y -1 cuando
2 se detecta S
*/
0 void AHeroCharacter::MoveForward(float Value)
2 {
1
if ((Controller != NULL) && (Value != 0.0f))
{
2
//Obtiene la rotacion actual
2
const FRotator Rotation = Controller->GetControlRotation();
2
3
// Crea el vector de direccion a partir de hacia donde est
2 rotado y aplica el movimiento
const FVector Direction =
4
2 FRotationMatrix(Rotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
5
}
2 }
6
2 /**
7 * Se llama cuando se detecta la entrada de tipo MoveForward
2 (Cuando el usuario toca las teclas A o D).
@param Value Value es igual a 1 cuando se detecta D y -1 cuando
8 se* detecta
A
2 */
9 void AHeroCharacter::MoveRight(float Value)
3 {
if ( (Controller != NULL) && (Value != 0.0f) )
0
{
3
//Determina la direccin del movimiento hacia los lados.
1 Notar que solo nos intereza la rotacion en el eje Y
const FRotator Rotation = Controller->GetControlRotation();
3
const FRotator YawRotation(0, Rotation.Yaw, 0);
2

3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
// Crea el vector de la direccin y aplica el movimiento
4
const FVector Direction =
4
FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
4
AddMovementInput(Direction, Value);
5
}
4 }
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6

Ya aqu si tenemos algunas cosas que comentar, pero de seguro a estas alturas tienes una
idea de todo. Primero, en SetupPlayerInputComponent usamos el parmetro que recibe
para configurar los mtodos que se van a llamar cuando se detecte cada una de las
entradas. O sea, con InputComponent->BindAxis(MoveForward, this,
&AHeroCharacter::MoveForward); estamos diciendo que cuando el Engine detecte la
entrada MoveForward, que como definimos ser cuando el jugador presione las teclas
W o S del teclado, se llamar el mtodo MoveForward. Y el mismo principio para la
otra entrada.
Ahora vamos a ver la implementacin del mtodo MoveForward. Este mtodo recibe un
parmetro float, que es el valor Scale que registramos en el Editor. O sea, cuando se
toque la W se llamar este mtodo con 1.0 como parmetro y cuando se toque la S se
llamar este mtodo con -1.0 como Value.
El mtodo lo que hace es determinar la rotacin que tiene el modelo y el vector en la
direccin a la que est orientado y mediante el mtodo AddMovementInput hacemos
que el personaje se mueva en esa direccin. Fjate que se calcula la direccin y como se
pasa Value que ser 1 o -1 entonces el personaje se mover hacia delante o hacia atrs
segn Value. AddMovementInput es un mtodo de APawn que permite aplicar un
movimiento al Pawn para el caso del personaje que no sea un cuerpo fsico, como el
nuestro. Para el caso del MoveRight fjate que es prcticamente lo mismo, pero al
calcular la direccin lo hacemos en base al eje Y y no con el eje X.
Listo, esto es todo lo que necesitamos. Compila y ejecuta el juego, cuando abra presiona
las teclas W,S,A,D del teclado para controlar al personaje. Cuidado no te caigas por los
bordes de la plataforma ;)
Umm pero an tenemos dos problemas con este movimiento. Primero, el personaje no
rota en la direccin del movimiento como sera lo lgico, y el otro problema es que a
pesar que se est moviendo sigue con su animacin de reposo. Vamos entonces a
solucionar estos dos problemas.
Primero, para solucionar el problema de la rotacin es muy fcil. Abre el
HeroCharacter.cpp y modifica el constructor para que te quede de la siguiente forma:
1 AHeroCharacter::AHeroCharacter(const class
PCIP)
2 FPostConstructInitializeProperties&
: Super(PCIP)
3 {
4
//Por defecto esta propiedad viene en true para el Character.
//Pero en nuestro modelo de desplazamiento, no queremos que el
5
6 personaje rote en base a la rotacin del Controller.
bUseControllerRotationYaw = false;
7
8
//Configuracin del componente CharacterMovement
9
1
//Al estar en true habilita para que el character se rote en la
0 direccin del movimiento al comenzar el movimiento.
CharacterMovement->bOrientRotationToMovement = true;
11
1
//Factor de rotacin para la propiedad anterior.
2
CharacterMovement->RotationRate = FRotator(0.0f, 540.0f, 0.0f);
1

3
1
4
1
//Bajamos un poco el valor por defecto de MaxWalkSpeed para que
5
el personaje camine un poco ms lento.
1
CharacterMovement->MaxWalkSpeed = 400.0f;
6 }
1
7
1
8
Recuerdas que el Character tiene un CharacterMovement verdad ?. Pues aqu lo que
hicimos fue modificar algunos valores para cambiar el comportamiento por defecto del
Character. Puedes revisar en el Editor desde el HeroCharacterBlueprint que creamos,
todas las propiedades que tiene el CharacterMovement, juega un poco con ellas para que
veas todo lo que se le puede definir al movimiento del Character.
Agregando animacin de caminando al personaje.
Vamos a trabajar ahora en el ltimo problema que tenemos, hacer que el personaje
cuando est en reposo tenga su animacin de reposo (como ahora) pero cuando est
caminando reproduzca la animacin de caminando, con esto veremos uno de los
mecanismos que nos da Unreal Engine para ligar dos animaciones de forma suavizada,
los Blend Space.
Blend Space es el Nodo del Animation Blueprint que nos permite hacer blending entre
dos animaciones en base a la entrada de valores. En Unreal tenemos dos tipos: el Blend
Space que es para varias entradas y el Blend Space 1D que es para una sola entrada.
Para este simple ejemplo usaremos el Blend Space 1D ya que necesitamos solamente
una entrada para lo que queremos lograr, la velocidad del desplazamiento.
Abre el Editor y dentro de la carpeta Animations en el Content Browser da clic derecho
para agregar un Animations/BlendSpace1D ponle de nombre IdleWalkBlendSpace1D y
dale doble clic para abrir el Editor de este elemento. Aqu la idea es la siguiente, decirle
las dos animaciones que harn blending segn el valor de una variable. En el panel de
las propiedades de IdleWalkBlendSpace1D en el X Axis Label escribe Speed (esto es
solo para una referencia, puede ser cualquier otra palabra que te represente el valor que
se tiene en cuenta para cambiar entre una animacin y otra). En el rango pon 0 y 100.
Ahora fjate que ms abajo tienes un espacio como de una grfica, arrastra hacia ah
desde el panel Asset Browser la animacin Idle y colcala al inicio del eje X, has lo
mismo para la animacin Walk y colcala al final del eje. Listo, ahora mueve el cursor
sobre el eje y fjate en el panel Preview como a medida que el valor se va modificando,
el modelo va cambiando de su estado Idle a Walk. Guarda y cierra este editor.

Configuracin del IdleWalkBlendSpace1D


Ahora vamos a modificar el HeroAnimBlueprint para en el State Machine al nodo Idle
cambiar su comportamiento. Abre el HeroAnimBlueprint ve desde el AnimGraph hasta
el nodo Idle (si quieres puedes cambiarle el nombre ahora a Idle/Walk) ya que dentro de
este nodo se manejarn estos dos estados. Entra para editarlo. Elimina el nodo de Idle
que estamos usando ahora y agrega el IdleWalkBlendSpace1D que acabamos de crear.
Como ves este Nodo a diferencia del anterior tiene un puerto de entrada con el nombre
Speed (que se lo definimos cuando lo creamos) por lo que para que funcione alguien le
tiene que suministrar este valor. En el panel MyBlueprint hay un icono con un +V que
dice Variable. Esto es para agregar una nueva variable al grfico. Da clic aqu y dale el
nombre de Speed a la variable, arrstrala para el espacio de trabajo y cuando te pregunte
Set/Get selecciona GET. Por ltimo conecta Speed a IdleWalkBlendSpace1D y este al
Final Animation Pose.

Ya tenemos el Nodo Idle/Walk listo, pero te estars preguntando a la variable Speed,


quien le da su valor ? Esto lo tenemos que definir en el EventGraph. Vamos a
implementar un algoritmo que en cada loop de la animacin obtenga el Pawn (que sera
nuestro personaje) despus que se llame al mtodo GetVelocity que retorna el vector de
desplazamiento que lleva el personaje en ese momento. Este vector por supuesto se
modifica gracias a la implementacin del MoveForward y MoveRight que hicimos
anteriormente en C++. Cuando tengamos la velocidad, obtenemos la distancia de ese
vector y vamos a usar ese valor para darle valor a la variable Speed. Todo esto lo vamos
a hacer en el HeroAnimBlueprint/EventGraph.
Ya vimos anteriormente como es el Visual Scripting en el Blueprint Editor as que no
tendrs problema y ser otro momento para repasar su funcionamiento. Vale la pena
aclarar en este punto, que como dijimos anteriormente, todo esto se puede hacer desde
programacin directo. Pero por ejemplo, la lgica del comportamiento de las
animaciones es uno de los casos donde es mucho mejor hacerlo en el Blueprint para que
quede todo el mecanismo de animacin del personaje en un solo lugar y poderlo repasar
y pre visualizar fcilmente.
Abre el HeroAnimBlueprint/EventGraph, agrega y conecta los Nodos para que te quede
igual que la imagen siguiente. No voy a repetir paso a paso todo el proceso, porque con
la explicacin que hicimos anteriormente del Blueprint Editor debes poder hacerlo por
tu cuenta y entender todo lo que hace el algoritmo.

Algoritmo del HeroAnimBlueprint/EventGraph con la lgica para setear el valor de la


variable Speed usada dentro del State Machine del personaje para cambiar entre las
animaciones de caminando y reposo.
Listo, compila y guarda el Blueprint y dale Play al juego Super verdad !! ya tenemos
nuestro personaje movindose por el terreno correctamente segn queramos y cuando

est detenido se anima con su animacin de reposo y cuando est caminando se anima
con su animacin de Walk. :)
Conclusin
Hasta aqu este tutorial de introduccin al Unreal Engine 4. En el prximo tutorial
modificaremos la cmara, los controles y el movimiento del personaje para hacer
nuestro juego un side-scroller style. Adems agregaremos algo de lgica al juego,
nuestro personaje tendr que lograr alcanzar todas las monedas que existan en el
escenario antes de un tiempo determinado, para poder ganar, de lo contrario perder y
tendr que comenzar de nuevo. Mientras djame saber tus comentarios :).

Tutorial: Cmo hacer un juego sidescroller 3D con UE4 ?


2014/09/29 por nan2cc 9 comentarios
Introduccin
En el tutorial pasado hicimos una introduccin general al Unreal Engine 4. Vimos varios
aspectos importantes como la jerarqua de clases que sigue el framework, el visual
scripting, la configuracin de las animaciones para el personaje, definimos
temporalmente una cmara fija a nuestro juego, entre otras cosas. Si no lo has visto,
debieras darle un vistazo antes de seguir con este.
Hoy vamos a crear la base del estilo de nuestro juego: un side-scroller 3D. Actualmente
estoy trabajando con mi equipo (www.spissa.com) en un Runner automtico, sidescroller 2D para iOS y Android. Puedes darte una vuelta por nuestro sitio en Facebook
para que ests al tanto de la salida. Si te gusta este estilo de juego, te aseguro que te
encantara el nuestro ;)
Como te deca, en este tutorial vamos a configurar la cmara del juego para lograr una
vista side-scroller. Vamos a agregar unas monedas al escenario y usar un mecanismo
simple de colisiones para que el personaje las pueda recolectar. Vamos a ensearle a
nuestro personaje a correr y saltar :). Vamos a ver varios macros de variables y
funciones de clase para la integracin entre el cdigo C++ y el Editor . . . y muchas
cosas ms. Listo ?! .. pues manos a la obra !!
Modificando el nivel desde el editor
Vamos a comenzar modificando un poco el nivel actual desde el editor para que se
acople ms al estilo de juego que queremos implementar. Como ya deca, vamos a
trabajar en un juego 3D side-scroller. La base de este estilo de juego es tener la cmara
paralela al personaje protagnico siguindolo contantemente en la misma posicin. El
personaje, por su parte, se mueve solamente en dos direcciones: hacia arriba/abajo
cuando salta y hacia izquierda/derecha cuando se desplaza.

Abre el editor con el proyecto UE4Demo que dejamos del tutorial pasado y comienza
eliminando los objetos visibles que no vamos a usar (las sillas, la mesa, la estatua). Solo
qudate con un objeto floor (piso). Despus, modifica el objeto floor usando las
herramienta de transformacin y escalado que tienes en la esquina superior derecha del
viewport. Despus crea copias del objeto, modifcalas indistintamente y reprtelas por el
nivel. Asegrate de dejar el Actor Play Start sobre una de las plataformas, para evitar
que el personaje cuando inicie el juego se caiga al abismo. En mi caso qued as ( tu
puedes usar mucho ms tu imaginacin para lograr algo mejor :) ):

Nivel modificado en el Editor para que se acople ms al estilo de nuestro juego

Como notars, al lanzar el juego se muestra un cartel rojo que dice: LIGHTING NEEDS
TO BE REBUILT. Esto pasa porque modificamos la geometra en el nivel y el motor
necesita recompilar las luces para que la iluminacin se adapte a la nueva geometra.
Puedes recompilar las luces desde el Toolbar/Build/Build Lighting Only. Vuelve a
correr, vers que todo volvi a la normalidad.
Bien, ya tenemos un nivel, muy bsico, pero suficiente para implementar y probar todo
lo que haremos hoy.
Configurando la cmara para un juego side-scroller.
En este punto es importante aclarar que el UE4 ya trae por defecto una plantilla para
comenzar un juego de este estilo. De hecho usaremos prcticamente lo mismo que usa
esta plantilla, pero la idea es hacerlo desde cero en este tutorial para entender bien el
porqu de las cosas.

Lo primero ser cambiar la cmara del juego. En el tutorial pasado configuramos una
cmara fija bastante simple, pero que nos sirvi para introducirnos tanto en el visual
scripting con el Blueprint Editor, como en la programacin en C++. Ya no usaremos
ms esta cmara. Elimina la actual implementacin que tengas de la cmara, si te
quedaste con la solucin por cdigo, comenta el cdigo dentro del Begin Play y si te
quedaste con la solucin en el Blueprint, elimina todos los nodos o elimina la conexin
que sale del Nodo BeginPlay con esto ltimo se rompe el algoritmo porque no continua
la ejecucin al lanzarse el BeginPlay pero se mantienen el resto de las conexiones y los
nodos en el Editor, por si los quieres para una referencia.
Vamos ahora a configurar un nuevo estilo de cmara. Esta vez lo haremos desde C++ en
nuestra clase Character. Siempre ten en cuenta que esto mismo lo puedes hacer tambin
desde el Editor, recuerda que tenemos una clase Blueprint que hereda de nuestra clase
HeroCharacter.h. Una buena prctica sera que te aventuraras una vez que veas lo que
haremos aqu, ha hacerlo por tu parte desde el Editor modificando el
HeroCharacterBlueprint.
Abre la clase HeroCharacter.h y y despus del macro
GENERATED_UCLASS_BODY() agrega las siguientes declaraciones:
/** Brazo para apoyar fijar la cmara al Character al estilo side-

1scroller */
2UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
3TSubobjectPtr<USpringArmComponent> SpringArm;
4
5/** Cmara del juego, es adjuntada al socket del brazo para lograr el
6estilo de cmara de un side-scroller */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
7TSubobjectPtr<UCameraComponent> SideViewCamera;
Lo que hicimos fue agregar dos variables de clase a nuestro HeroCharacter, pero lo que
seguro ms te llama la atencin es el macro UPROPERTY que incluimos en cada
variable. Este macro nos sirve para definir si queremos reflejar o no estos atributos en el
Editor y que opciones tendremos. Como vimos, una de las cosas geniales que tiene
Unreal Engine 4 es la perfecta integracin entre el cdigo y el editor y este macro es
uno de los que nos ayuda a esto. A este macro le podemos pasar parmetros:
VisibleAnywhere: Indica que esta propiedad ser visible en el panel de propiedades en
el Editor.
BlueprintReadOnly: Esta propiedad podr ser leda desde un VisualScript en el
Blueprint, pero no modificada.
Category: Permite especificar un nombre de categora bajo la que se mostrar esta
propiedad en el Editor
Puedes ver una referencia detallada de todos los parmetros que podemos indicar para
UPROPERTY en la clase Runtime/CoreUObject/Public/UObject/ObjectBase.h dentro
del namespace UP. Para llegar rpido puedes dar clic sobre cualquiera de las categoras
con la tecla cmd presionada.

Despus que implementemos el constructor donde inicialicemos estas variables, vamos


a ver en el editor el resultado que tiene definirlas con este macro.
Estas dos variables de clase que creamos para HeroCharacter son de un nuevo tipo de
datos que no hemos usado antes. La primera variable que creamos la nombramos
SpringArm y es de tipo USpringArmComponent, pero fjate que usamos para definirle
el tipo, la clase parametrisada TSubobjectPtr. Con TSubobjectPtr podemos usar el
mtodo CreateDefaultSubobject del objeto PCIP que recibimos en el constructor para
crear una instancia de cualquier tipo de dato. Lo haremos en un segundo.
USpringArmComponent nos permite fijar un componente a su padre a una distancia
fija. Usaremos este componente para fijar la cmara del juego a una distancia fija del
personaje.
Adems, creamos la variable de clase SideViewCamera de tipo UCameraComponent. El
nombre de la clase es bastante descriptivo, esta ser la cmara de nuestro juego :)
Hecho esto vamos a inicializar estas variables en el constructor de la clase. Abre el
archivo HeroCharacter.cpp y agrega antes de terminar la implementacin del
constructor el siguiente bloque:
1 //Inicializando la instancia del USpringArmComponent
= PCIP.CreateDefaultSubobject<USpringArmComponent>(this,
2 SpringArm
TEXT("CameraBoom"));\
3
4 //Agregando el springArm al RootComponent del Character (la capsula
5 de colisin)
6 SpringArm->AttachTo(RootComponent);
7
8 //bAbsoluteRotation nos permite definir si este apoyo para la cmara
junto con el player.
9 rotar
//En este caso no queremos que rote junto al character
1 SpringArm->bAbsoluteRotation = true;
0
11//La distancia entre el brazo y su objetivo. Este valor es el que
1 define la distancia de la cmara.
2 //Prueba con distintos valores para que veas el resultado.
1 SpringArm->TargetArmLength = 500.f;
3 //Offset que tendr el Socket.
1 //Un Socket es un punto de anclaje para otros componentes.
4 //Por ejemplo, para el caso de un personaje podemos definir que
1 tenga un socket en la zona de la mano
5 //de esta forma le podemos agregar otro componente (como un arma,
por ejemplo) en la mano
1 //En nuestro SpringArm, en este socket es donde se agregar la
6 cmara
1 SpringArm->SocketOffset = FVector(0.f,0.f,75.f);
7
1 //La rotacin relativa que tendr este brazo con respecto al padre.
8 //En este caso queremos que este rotada en el eje Y 180 grados para
que quede paralela al character a su mismo nivel.
1 //De esta forma logramos el clsico estilo de cmara en los side9 scrollers
2 SpringArm->RelativeRotation = FRotator(0.f,180.f,0.f);
0

2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3

// Creando la intancia del tipo UCameraComponent


SideViewCamera = PCIP.CreateDefaultSubobject<UCameraComponent>(this,
TEXT("SideViewCamera"));
//El mtodo AttachTo nos permite agregar un objeto a otro objeto en
un socket determinado. Recibe dos parmetros.
//el primero, el objeto al que vamos a anclarnos, en este caso el
springArm y el nombre del socket donde lo vamos a anclar
//SocketName de USpringArmComponent retorna el nombre del Socket de
este componente.
SideViewCamera->AttachTo(SpringArm,
USpringArmComponent::SocketName);

Prstale atencin a los comentarios de cada lnea para que puedas entender cada una lo
que hace. En general creamos y configuramos el objeto USpringArmComponent y lo
agregamos al Character. Despus, creamos y configuramos el objeto
UCameraComponent (la cmara del juego) y la agregamos al USpringArmComponent
para fijarla a una distancia del Character. Notar que las instancias de los objetos las
creamos a partir del objeto que recibimos en el constructor, con
PCIP.CreateDefaultSubobject.
Listo, compila y ejecuta el juego, ahora tendrs la vista del juego al estilo sidescroller :). Puedes probar moverte por el nivel que creaste para que veas como la cmara
te sigue en todo momento a la misma distancia.

Nueva vista del juego con la cmara configurada al estilo de un side-scroller

No cierres el editor, vamos a ver ahora a HeroCharacterBlueprint. En el tutorial pasado


este blueprint lo creamos dentro de la carpeta Character. brela y activa el modo
Components (esquina superior derecha). Fjate que ahora en el panel de Componentes
del Character tienes un nuevo objeto SpringArm y este tiene como hijo a
SideViewCamera. Puedes revisar para que veas que tiene las propiedades que definimos
desde programacin. Desde aqu tambin puedes variar todas las propiedades por
defecto. Juega un poco con ellas para que veas todo lo que puedes lograr.
Para que veas en la practica el efecto de los atributos que le pasamos al UPROPERTY:
Regresa al cdigo y elimina el atributo VisibleAnywhere que le pusimos al macro
UPROPERTY y compila de nuevo. Cuando abras el HeroCharacterBlueprint en el
editor a pesar de poder ver los componentes, al seleccionarlo no se muestran las
propiedades en el panel de detalles.
Modificando los controles del juego para un side-scroller
Ya nuestro juego tiene el estilo de cmara que queremos, pero te habrs dado cuenta de
que en este estilo de juego no sirve mucho el control actual, ya que el personaje puede
moverse tanto en el eje X como en el Y, cosa que es muy poco comn en los sidescroller. Por tanto, vamos a modificar un poco los controles para ajustarlos ms a este
estilo de juego. Adems agregaremos dos nuevos controles y acciones nuevas para
nuestro personaje: correr y saltar.
Supongo que ya tengas ideas de como hacer esto si seguiste el tutorial anterior. Entra
desde el Editor en Edit/ProjectSettings/Input. Deja solamente MoveRigth. Ahora vamos
a agregar otro tipo de input, ActionBinding. Estas entradas, a diferencia de los
AxisBinding, son usadas para ejecutar acciones determinadas, saltar por ejemplo o abrir
una puerta. Crea una nueva entrada de este tipo, dale de nombre Jump y selecciona la
barra espaciadora. Adems si te fijas puedes definirle que para que se ejecute tenga que

estar presionada otra tecla simultneamente. En este caso no marques ninguna,


solamente con tocar la barra espaciadora el personaje saltar.

Nueva configuracin de los controles del juego. Ahora con un control para saltar

Ahora vamos al cdigo. Primero, ya no necesitamos el mtodo MoveForward de


HeroCharacter, elimina la declaracin de este mtodo en el .h y la implementacin del
.cpp. Adems, dentro del mtodo SetupPlayerInputComponent elimina el BindAxis del
MoveForward. Por ltimo, tenemos que modificar el cdigo del mtodo MoveRight
para cambiar su implementacin, ya que actualmente lo que hace el personaje cuando
tocamos las teclas A o D es rotar su posicin. En este caso lo que queremos es que se
mueve hacia delante y atrs respectivamente. Modifica el mtodo MoveForward para
que quede as:
1
2 /**
* Se llama cuando se detecta la entrada de tipo MoveForward
3 (Cuando el usuario toca las teclas A o D).
4 * @param Value Value es igual a 1 cuando se detecta D y -1 cuando
5 se detecta A
6 */
void AHeroCharacter::MoveRight(float Value)
7 {
8
if ( (Controller != NULL) && (Value != 0.0f) )
9
{
// Agrega un vector de movimiento hacia la derecha o la
1
izquierda
segun el valor de Value
0
AddMovementInput(FVector(0.f,-1.f,0.f), Value);
11
}
1 }
2

Como puedes notar, el mtodo qued mucho mas simple que la anterior implementacin
y ya debes entender sin problema que hace. Simplemente aplicamos un vector de
movimiento que afecta solo un eje con el valor de Value. Por lo que cuando el usuario
toque la tecla D el personaje se mover hacia delante (hacia la derecha) y cuando toque
la tecla A se mover hacia la izquierda.
Ahora tenemos que implementar el mtodo que se llamar cuando el usuario toque la
barra espaciadora para hacer saltar a nuestro hroe. Muy simple, agrega la siguiente
lnea al mtodo SetupPlayerInputComponent:
InputComponent->BindAction("Jump", IE_Pressed, this,

1&ACharacter::Jump);

Fjate en una cosa, el mtodo que se llamar es ACharacter::Jump. O sea, Jump es un


mtodo implementado en la clase base de nuestra clase, no en nuestra propia clase
HeroCharacter. Este mtodo ya tiene implementado todo lo necesario para hacer saltar
al personaje. No es poca la ayuda que nos da el Framework ehh ?? :)
Listo, compila y ejecuta el juego y toca las teclas A y D para que veas como el personaje
se mueve correctamente por el escenario, y aunque toques las teclas W o S no pasar
nada. Ahora toca la barra espaciadora, eehhh !!! nuestro personaje ya sabe saltar
tambin :) . . . pero algo est mal aqu. S, el personaje salta, pero a pesar de estar
saltando sigue reproduciendo la animacin de caminar. Pues claro, recuerda que solo le
tenemos dos animaciones, y no hemos hecho nada para el caso en el que est saltando.
Vamos a solucionar esto.
Configurando las animaciones para el salto del personaje
Del tutorial pasado tenemos los recursos que supuestamente nos entreg nuestro equipo
de diseo para el personaje principal. Entre ellos tenemos 3 FBX de animaciones
Jump_End.FBX, Jump_Loop.FBX, Jump_Start.FBX y Run.FBX. Imprtalas dentro de
la carpeta Animations. Puedes abrirlas en el Persona Editor para que les des un vistazo.
Como notars tenemos tres fbx distintos, bsicamente tres animaciones separadas para
el salto. Y te preguntars: Esto por qu? te cuento. Cuando comenzamos a
desarrollar nuestro actual proyecto (puedes darle un vistazo aqu :)) en este juego el
personaje salta mucho y a distintas alturas, lo mismo hace un salto simple chiquito, que
un salto desde una gran altura y est ms tiempo en el aire. El problema que tenamos
con esto es que cuando el salto era de gran altura, donde el personaje estaba mucho
tiempo en el aire, cuando iniciaba el salto reproducamos la animacin de saltando, que
la tenamos en una sola parte, y cuando la animacin terminaba su tiempo, como el
personaje aun no haba cado en el suelo, se quedaba con el ultimo frame de la
animacin y totalmente tieso, hasta que caa en el suelto y entonces segua animndose
normalmente. Por este motivo es que en la mayora de los casos es necesario separar las
animaciones del salto. Tendremos el pedazo de la animacin cuando inicia el salto,
despus una animacin que reproduciremos en repeticin (en loop) mientras el
personaje este en el aire, y por ultimo el trozo de animacin cuando llega al suelo. De
esta forma tendremos todo el ciclo del salto animndose perfectamente
independientemente de la altura.

Vamos a configurar esto en el Blueprint de las animaciones del personaje. Como ya


sabes, para el sistema de animacin se usa una maquina de estado que nos permite
separar perfectamente todos los estados en los que estar el personaje y configurar la
animacin para cada estado. Actualmente la maquina de estado de nuestro personaje es
sumamente simple. Solamente tiene un estado Idle/Walk. Vamos a modificarla para
agregar los estados del salto.
Dentro del HeroAnimBlueprint/AnimGraph, entra en la maquina de estado. Arrastra
desde el nodo Idle/Walk para crear un nuevo nodo, ponle el nombre de JumpStart,
arrastra desde JumpStart para crear otro nodo y ponle JumpLoop. Repite el
procedimiento desde JumpLoop para crear un tercer estado JumpEnd y por ultimo
conecta el estado JumpEnd con Idle/Walk para cerrar el ciclo. Te quedar as:

Nueva maquina de estado del Character, con los estados del salto

Lo que acabamos de hacer aqu es definirle 3 nuevos estados que va a tener el personaje
y el orden en los que podr alcanzarlos. O sea, el personaje podr estar en
reposo/corriendo y de ah puede pasar al estado de JumpStart (inicio del salto). De este
estado JumpStart puede pasar a JumpLoop (ciclo del salto). De JumpLoop puede pasar a
JumpEnd y por ultimo de JumpEnd regresa nuevamente a Indle/Walk. Fjate que la
conexin entre los estados es una flecha que marca la direccin, o sea, cual es el estado
origen y cual el destino. Es bastante lgico, si lo imaginas un poco o te paras un
segundito y saltas :) reproducirs estos 4 estados y la transicin por cada uno de ellos.
Cada estado tiene sobre la flecha de la transicin un iconito arriba que representa la
condicin que define cuando es que se pasar de un estado a otro. Esta condicin las
tenemos que programar nosotros (mediante visual scripting con el Blueprint Editor). El
primer caso sera cuando el personaje est en Idle/Walk y comienza un salto. La
condicin que usaremos para pasar a este estado ser muy simple, crearemos una
variable BOOL que nos permita saber si el personaje est en el aire o no y si est en el
aire va a pasar al estado de JumpStart.
Da doble clic en el icono de la transicin y entrars en el modo edicin de este
elemento, Por defecto tiene un nodo Result con la descripcin Can Enter Transition, este

nodo espera un parmetro bool (true/false) que le dir si la maquina activa este estado o
no, o sea, si se efecta la transicin. Crea y agrega una nueva variable, como mismo
hicimos en el tutorial pasado, pero de tipo bool. Ponle de nombre IsInAir o cualquier
otro nombre identificativo que se te ocurra. Agrgala al blueprint en modo GET. Ahora
conecta el Puerto de salida de esta variable al Puerto de entrada del nodo Result.
Lo que acabamos de programar aqu mediante visualscripting es: Si la variable IsInAir
tiene valor true, entonces ejecuta esta transicin. Lo que quiere decir, que el personaje
pasara para el estado de JumpStart.

VisualScript de la transicin entre Idle/Walk y JumpStart

Guarda y sale del modo de edicin de la transicin de Idle/Walk a JumpStart y entra en


el modo de edicin del nodo JumpStart para definir que animacin se va a reproducir
aqu. Arrastra hacia al blueprint la animacin JumpStart que tienes en los recursos y
conctala al nodo final. Para el caso de las animaciones JumpStart y JumpEnd,
queremos que se reproduzcan solo una vez, o sea que no se reproduzcan en ciclo como
hemos hecho hasta ahora con las animaciones de reposo y caminando, ya que la idea es
reproducir JumpStart, al terminar, reproducir JumpLoop (esta s en ciclo) hasta que el
personaje llegue al suelo y por ultimo reproducir JumpEnd, una sola vez. Selecciona el
nodo de la animacin JumpStart y en el panel de propiedades desmarca la opcin Loop.

VisualScript del nodo JumpStart

Ahora, cual sera la condicin para pasar de JumpStart a JumpLoop?. Pues para este
caso usaremos un nuevo nodo. La idea es determinar cuando se est a punto de acabar la
animacin de JumpStart para comenzar a reproducir el loop. Da doble clic en el icono
de transicin de JumpStart a JumpLoop, como ya vimos, por defecto tenemos el nodo
Result al que hay que conectar la salida del algoritmo que preparemos aqu y que
determina cuando pasa el personaje a este estado. Agrega un nuevo nodo de tipo Time
Remaining (Ratio) para Jump_Start Asset. Este nodo nos permite tener en todo
momento el tiempo que le va quedando a la animacin para que termine. Agrega ahora
otro nodo de tipo float < float. Este nodo es un mtodo que nos permite saber si un
parmetro A es menor que otro B. Conecta el puerto de salida del nodo TimeRemaining
al puerto de arriba de entrada de la comparacin. Para el segundo parmetro de la
funcin menor que, no vamos a conectar ningn nuevo nodo, sino que vamos a definir
un valor a mano. Como queremos que se comiese a reproducir Jumploop ya cuando est
a punto de terminar el JumpStart, pon en el campo del segundo parmetro de la funcin
menor que: 0.1. Por ultimo conecta la salida de esta funcione al nodo Result. Te
quedara de la siguiente forma:

VisualScript de la transicin de JumpStart a JumpLoop

Bsicamente lo que programamos aqu fue: Si el tiempo que le queda a la animacin por
terminar es menor que 0.1 pasa al siguiente estado.
Guarda estos cambios, sale del modo de edicin de la transicin y entra en el modo
edicin del estado JumpLoop, agrega la animacin JumpLoop y conctala al Result. A
diferencia de JumpStart, JumpLoop si queremos que se reproduzca en ciclo ya que es
esta la animacin que se estar reproduciendo mientras el personaje est en el aire. Para
esto, rectifica que en el panel de propiedades del nodo que representa la animacin,
tenga marcado el atributo Loop.

VisualScript del nodo JumpLoop

Vamos ahora a configurar la transicin de JumpLoop a JumpEnd. JumpEnd es la


animacin cuando termina el salto, para pasar al estado JumpEnd simplemente sera
cuando el personaje deje de estar en el aire. Para esto ya tenemos la variable bool
isInAir as que vamos a usarla. Da doble clic en el icono que representa la transicin
entre JumpLoop y JumpEnd, agrega la variable isInAir como GET un segundo !!
isInAir nos dice si el personaje est en el aire, pero, cmo saber si el personaje NO est
en el aire ?. Sera la negacin de isInAir verdad ?. Entonces, agrega al blueprint un nodo
de tipo NOT. Este nodo retorna la negacin de su entrada. Conecta isInAir a NOT y
NOT a Result. Listo !, en cuanto el personaje deje de estar en el aire pasar a este
estado.

VisualScript de la transicin de JumpLoop a JumpEnd

Sale del modo de edicin de esta transicin, entra en el modo de edicin del estado
JumpEnd. Arrastra y conecta al Final Pose la animacin JumpEnd y desmrcale la
opcin de loop.

VisualScript del estado JumpEnd

Por ltimo, tenemos que definir las condiciones para pasar de JumpEnd de nuevo a
Idle/Walk. JumpEnd es la animacin que termina el salto, ya el personaje est en el
suelo pero recuperndose de la cada. Por lo que simplemente para pasar a Idle/Walk es
esperar a que la animacin JumpEnd est a punto de terminar, como mismo hicimos de
JumpStart a JumpLoop. Esto lo debes poder hacer por tu cuenta, as que intntalo ;)
te tiene que quedar as:

VisualScript de la transicin de JumpEnd a Idle/Walk

Muy bien, ya tenemos la maquina de estado del personaje lista, pero nos falta una cosa.
En estos estados estamos usando una nueva variable IsInAir solo en modo GET, pero
recuerda, como mismo hicimos para Speed, en algn punto esta variable tiene que tomar
valor.
Cierra el AnimGraph y abre el EventGraph, agrega un nodo GetMovementComponent
conecta el puerto de salida del TryGetPawnOwner que tenemos desde el tutorial pasado
al puerto de entrada del GetMovementComponent, agrega otro nuevo nodo Is Falling,
conecta el puerto de salida de GetMovementComponent al de entrada del IsFalling.
Agrega la variable IsInAir en modo SET y conecta la salida de IsFalling a la entrada de
IsInAir. Por ltimo, conecta el puerto blanco de salida de SET Speed al de entrada de
SET IsInAir para la continuidad del algoritmo.

EventGraph del HeroAnimBlueprint modificado para darle valor a la variable IsInAir


cuando el personaje est en el aire

Si has llegado hasta aqu desde el tutorial anterior no debes tener problema en entender
que acabamos de hacer aqu. Obtenemos el MovementComponent del Character, este
tiene un mtodo IsFalling que retorna true/false si el usuario est en el aire o no. Este
mtodo es el que usamos para settear el valor de la variable IsInAir.
Listo, ya tenemos la nueva maquina de estado para nuestro personaje. Compila el
AnimationBlueprint y corre el juego. Toca la barra espaciadora . . . ya nuestro hroe
sabe saltar tambin :)

Personaje en el medio de un salto animndose correctamente

Implementando mecanismo para que el personaje corra !!


Ya tenemos a nuestro hroe que sabe caminar, reposar y saltar, pero algo que nos va
faltando y es clsico en un side-scroller, la posibilidad de correr, para obtener ms
impulso, saltos ms largos etc. Quin no recuerda en uno de los ltimos niveles del
primer Super Mario el hueco grandsimo que solo podamos saltar si lo hacamos con
mucho impulso ehh? :) . . . Pues bien, vamos a darle esta misma habilidad a nuestro
hroe. Vamos a implementar que cuando se est caminando con la tecla Shift presionada
el personaje corra.
Primero, abre el editor y agrega en los controles una nueva entrada de tipo
ActionBinding ponle el nombre de Run y selecciona al tecla LeftShift. Cierra el editor y
abre la clase HeroCharacter.cpp agrega dentro del mtodo SetupPlayerInputComponent
las dos siguientes lneas:
1//Le dice al motor que cuando detecte
2estando presionada la tecla, llame al
InputComponent->BindAction("Run",
3&AHeroCharacter::ToggleRunState);
4
5//Le dice al motor que cuando detecte

la entrada de tipo Run (Shift)


metodo ToggleRunState.
IE_Pressed, this,

la entrada de tipo Run (Shift)

al soltar la tecla, llame al metodo ToggleRunState.


InputComponent->BindAction("Run", IE_Released, this,
&AHeroCharacter::ToggleRunState);

Fjate en un detalle, estamos llamando al BindAction para la entrada Run dos veces y
pasndole el mismo mtodo ToggleRunState (que vamos a implementar ahora) pero la
diferencia entre uno y otro es que el segundo parmetro especifica exactamente cuando
es que se va a llamar al mtodo. IE_Pressed cuando se presione la tecla Shift y
IE_Release cuando se suelte. Lo que queremos hacer es que si se est tocando el shift el
personaje corre pero si se suelta deja de correr, algo parecido a la misma combinacin
que tenamos que hacer en el Super Mario para el super salto !! :)
Bien, ahora vamos a implementar el mtodo ToggleRunState. Agrega en el .h de
HeroCharacyer.cpp la declaracin del mtodo:
1 /**
2 * Se llama cuando el motor detecta la entrada Run
3 * Intercambia el estado de correr del personaje
4 */
void ToggleRunState();
5
Pasa a la .cpp y agrega la implementacin:
1
2
3 /**
* Se llama cuando el motor detecta la entrada Run
4 * Intercambia el estado de correr del personaje
5 */
6 void AHeroCharacter::ToggleRunState()
7 {
//Si el atributo MaxWalkSpeed del CharacterMovement est en 400.f lo
8 aumentamos a 900.f para que el personaje se mueva mas rpido
9 //De lo contrario lo volvemos a poner en 400.f para que regrese a su
1 velocidad de caminar.
if(CharacterMovement->MaxWalkSpeed == 400.0f)
0
CharacterMovement->MaxWalkSpeed = 900.0f;
11
else
1
CharacterMovement->MaxWalkSpeed = 400.0f;
2 }
1
3
Muy simple, por defecto la velocidad de desplazamiento del personaje es 400 cuando
este mtodo se llama por primera vez (cuando se presiona shift) el MaxWalkSpeed est
en 400 y se pasa a 900, lo que har que el personaje de desplace ms rpido, y cuando
se suelte el Shift se va a llamar de nuevo y se volver a poner la velocidad en 400,
disminuyendo el desplazamiento.
Una buena tarea sera que intentes implementar este mecanismo de correr en el
Blueprint del HeroCharacter. Recuerda eliminar el cdigo C++ si vas a usar el
Blueprint. Te tendra que quedar as:

Variante en el Blueprint de la funcionalidad del correr

Yo en lo personal prefiero siempre mantener toda la lgica del personaje desde C++,
pero ese ejercicio te puede servir para tomar ms soltura en el Blueprint Editor que tanto
llama la atencin :).
Otra buena tarea sera que expongas los valores mximo y mnimo del MaxWalkSpeed
en el Editor para que se puedan modificar fcilmente sin necesidad de llegar al cdigo.
Ya sabes que tendrs que usar el macro UPROPERTY, pero este si no te dir como tiene
que quedarte, intntalo por tu cuenta ;)
Compila y ejecuta el juego, a medida que estas caminando deja presionada la tecla shift,
vers que el personaje se desplaza mucho ms rpido, pero muy feo ya que solamente se
afecta su desplazamiento pero no se afecta la animacin.
Agregando la animacin de correr al personaje
Vamos a agregar otra animacin a nuestro personaje, para que cuando est corriendo se
anime correctamente. Para esto usaremos el mismo estado Idle/Walk que ya tenemos,
pero ms aun, dentro de este usaremos el mismo nodo con el que hacemos blend entre
las animaciones de Idle y Walk. Una sper potencialidad de este nodo es que podemos
agregarle ms animaciones, no solo dos. La idea ser modificarlo para configurarle tres
puntos de control y no dos como tenemos ahora. Uno al inicio del grafico con la
animacin Idle, otro en el medio con la animacin Walk y otro al final con la animacin
Run.
Importa Run.FBX de los recursos para el proyecto. Abre el IdleWalkBlendSpace1D que
creamos en el tutorial pasado. Cmbiale la propiedad X Axis Range a 900 (que es el
valor que toma el personaje al correr) y da clic en el botn Apply Parameter Changes.

Ahora agrega al inicio del grfico la animacin de Idle, en el medio la animacin de


Walk y al final la animacin de Run. Asegrate de tener marcada la opcin de Enable
Preview BlendSpace y mueve el cursor sobre el grfico para que veas como se van
haciendo los blend, segn el valor de speed, entre reposo/caminando/corriendo. Sper
genial y fcil ehh ??.

Nueva configuracin del IdleWalkBlendSpace1D para Idle/Walk/Run

Guarda, ejecuta el juego y prueba correr. Ya nuestro personaje camina y corre


perfectamente.

Personaje corriendo con las teclas D+Shift presionadas

Agregando monedas para recolectar en el nivel


Ya tenemos nuestro personaje movindose por el escenario caminando, corriendo y
saltando al estilo side-scroller. Pero ir caminando por ah sin nada que hacer es algo

aburrido, no ? Vamos a tratar de mejorar esto un poco :) . . . vamos a implementar la


posibilidad de recolectar monedas por todo el escenario. En futuros tutoriales veremos
que gana nuestro hroe con estas monedas.
Primero, necesitamos el modelo de la moneda. En el MarketPlace de seguro que podrs
encontrarte muchsimos StaticMesh que puedas usar como moneda que nuestro
personaje pueda recolectar. Te recomiendo que te tomes un tiempo para recorrer el
MarketPlace, de seguro te encontrars cosas que te encantarn y muchas FREE ! :D
De cualquier forma, puedes bajar de aqu el FBX de una moneda MUY SIMPLE Y FEA
:S porque ya te he comentado que se me da muy mal el modelado 3D, pero perfecta para
nuestro tutorial. Importa este FBX al proyecto (yo cre una carpeta Coin). En la ventana
de importar vers que Unreal detecta que este es un StatickMesh, expande la opcin
avanzada y marca las opciones material y texture. Esto para que importes tambin el
material que tiene aplicado el modelo, que igual, es extremadamente simple pero le da
el look de moneda, por su color amarillo.
Bien, ya con el recurso importado vamos a crear la clase C++ que encapsular toda la
lgica de la moneda. Crea una nueva clase desde el editor de nombre Coin. En este caso
que herede de Actor. Cuando el Editor te pregunte si quieres abrir la clase en el IDE dile
que s. Modifica el .h de la clase para que te quede de la siguiente forma:
1 /** Representa una moneda. El personaje puede capturarla
con ella */
2 colisionando
UCLASS()
3 class ACoin : public AActor
4 {
GENERATED_UCLASS_BODY()
5
6
/**
7
* USphereComponent es un componente en forma de esfera
8 generalmente
usado para detectar colisiones simples
9
* Este ser el Root de la moneda y con l detectaremos las
1 colisiones entre el personaje y la moneda
*/
0
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
11
TSubobjectPtr<USphereComponent> BaseCollisionComponent;
1
2
/** StaticMesh de la moneda, ya lo usamos anteriormente con el
1 Character. En l tendrmos la instancia de el StaticMesh de la
3 moneda */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
1
TSubobjectPtr<UStaticMeshComponent> CoinMesh;
4
1
/** Simple variable booleana para activar o no la moneda */
5
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Coin)
1
bool bIsActive;
6 };
1
7
1
8
1
9

2
0
2
1
Prstale atencin a los comentarios, como siempre, para los detalles. Bsicamente lo
que hacemos es definir el atributo BaseCollisionComponent que ser el componente
raz de nuestra moneda, y el que usaremos para detectar colisiones con ella y un
UStaticMeshComponent para poder definir el StaticMesh que representar a la moneda
en el nivel. Por ltimo el atributo bIsActive que lo usaremos como bandera para
desactivar la moneda cuando se colisione con ella.
Pasa ahora a la .cpp y modifica el constructor para que te quede as:
1
2
3
4 ACoin::ACoin(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
5
{
6
//Crea la instancia del USphereComponent
7
BaseCollisionComponent =
8 PCIP.CreateDefaultSubobject<USphereComponent>(this,
9 TEXT("BaseSphereComponent"));
1
//Inicializa el RootComponent de este Actor con el
0
USphereComponent
11
RootComponent = BaseCollisionComponent;
1
2
//Crea la instancia del UStaticMeshComponent
1
CoinMesh =
3 PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this,
1 TEXT("CoinMesh"));
4
//Agregamos el UStaticMeshComponent como hijo del root component
1
CoinMesh->AttachTo(RootComponent);
5
1
//Por defecto la moneda estar activa
6
bIsActive = true;
1 }
7
1
8
Aqu instanciamos un USphereComponent como el RootComponent de nuestra
moneda. Creamos la instancia del UStaticMeshComponent que despus configuraremos
desde el editor, lo agregamos al RootComponent y por ultimo inicializamos en true
bIsActive. Ya que queremos que por defecto la moneda est active.
Agregando monedas al nivel

Vamos ahora a crear el Blueprint de la moneda, como mismo hicimos con el Character
en el tutorial pasado. Entra en la carpeta Coin del ContentBrowser, clic
derecho/Blueprint y selecciona Coin como clase base, dale de nombre CoinBlueprint.
Como vers, est compuesta por los mismos componentes que definimos en el
constructor un USphereComponent como RootComponent y un
UStaticMeshComponent. Despliega el CoinMesh y selecciona el StaticMesh que
importamos para la moneda.

Seccin Components del CoinBlueprint. Agregndole el StaticMesh

Ahora, vamos a agregar algunas monedas al escenario. Busca en el ContentBrowser el


CoinBlueprint y arrstralo al nivel en lugares donde quieras que salga la moneda para
que el personaje las pueda alcanzar. Una cosa importante a tener en cuenta, recuerda que
en este estilo de juego el personaje siempre tendr un Y fija por lo que tienes que
asegurarte de poner las monedas en la misma Y del personaje para que cuando camine
en direccin de la moneda pueda colisionar con ella. Mi nivel es muy simple, qued as:

Nivel en edicin con dos monedas agregadas.

Ya tenemos las monedas en el nivel, pero poco se puede hacer con eso. Si caminas hacia
las monedas no pasa nada, adems las monedas se ven muy feas estticas ah sin
moverse. Vamos a arreglar estas cosas
Simple mecanismo de colisin para recolectar las monedas
Como pudiste ver, ahora mismo cuando el personaje le pasa por arriba a la moneda no
pasa nada, esta sigue ah como si nada pasara. Vamos a solucionar esto implementado la
lgica para detectar cuando el personaje est sobre una moneda. De momento ser
simple nuestra implementacin, lo que haremos es incrementar un valor de Monedas
recolectadas que tendremos en nuestro personaje y llamar al mtodo OnCollected() que
crearemos en la moneda para ponerla inactiva, eliminarla del nivel y temporalmente
imprimir un log en la pantalla para debuguear este mecanismo.
Abre la clase HeroCharacter.h ya agrega las declaraciones siguientes:
1
2 /** Cantidad de monedas recolectadas por el personaje */
3 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Coins)
int32 CoinsCollected;
4
5 /** Se llama constantemente en el Tick del personaje para determinar
6 si se est colisionando con una moneda */
7 void CollectCoins();
8
9 /**
ejecuta automticamente por el Engine en cada frame del juego
1 ** Se
@param DeltaSeconds la diferencia en segundos entre el frame
0 pasado y el actual
11 */
1 virtual void Tick(float DeltaSeconds) OVERRIDE;
2
Vamos a comentar un poco cual es la lgica que usaremos. Todos los Actors en Unreal
Engine cuentan con el mtodo Tick. Este mtodo es llamado automticamente por el
Engine en cada frame del juego. Si estas leyendo este tutorial probablemente ests
familiarizado con el desarrollo de juegos, al menos la teora, y sabrs de sobra la
importancia de este mtodo. Bsicamente, todos lo algoritmos que queramos que estn
en constante ejecucin por un Actor determinado tiene que ir dentro de este mtodo
Tick. El mtodo Tick recibe como parmetro un float que es la variacin en segundos
entre un frame y el anterior. Ese valor es de mucha ayuda para usarlo como
multiplicador a la hora de modificar la posicin del personaje o la rotacin del actor
para que esto se ejecute dependiente del framerate que tenga el juego en ese momento y
evitar saltos en caso que la ejecucin del juego baje el framerate.
Entonces, lo que haremos ser tener en constante ejecucin el mtodo CollectCoins y
este mtodo lo que har ser determinar si hay alguna moneda dentro del
CapsuleComponent del Character, si es as, es que est arriba de una moneda.

Abre HeroCharacter.cpp y antes de terminar la implementacin del constructor agrega la


lnea CoinsCollected = 0. Muy simple, al crearse el Character no ha recogido ninguna
moneda. Ahora agrega la implementacin del mtodo CollectCoins() y Tick
1 /** Se llama constantemente en el Tick del personaje para determinar
se est colisionando con una moneda */
2 si
void AHeroCharacter::CollectCoins()
3 {
4
//Arreglo de AActors para guardar temporalmente todos los Actors
5 que se detecten que estn colisionando con el personaje
TArray<AActor*> CollectedActors;
6
7
cuenta con el mtodo GetOverlappingActors.
8 Este//CapsuleComponent
metodo nos retorna en la llamada dentro del arreglo que le
9 pasamos por parmetro
1
//todos los objetos que estan dentro de la capsula en ese
0 momento.
CapsuleComponent->GetOverlappingActors(CollectedActors);
11
1
//Recorremos todos los objetos dentro del CapsuleComponent
2
for(int32 i = 0; i < CollectedActors.Num(); i++)
1
{
3
1
//Como el arreglo es de AActors tenemos que catear cada
elemento
a ACoin antes de usarlo
4
ACoin
*Coin = Cast<ACoin>(CollectedActors[i]);
1
5
//Nos aseguramos que la moneda est activa y que no ha sido
1 llamado an el mtodo Destroy
6
if(Coin != NULL && !Coin->IsPendingKill() && Coin1 >bIsActive)
{
7
//Incrementamos la cantidad de momendas recolectadas
1
CoinsCollected++;
8
1
//Por ltimo llamamos al OnCollected de la moneda para
9 ejecutar toda la lgica de la moneda cuando esta es tomada por el
2 personaje
Coin->OnCollected();
0
}
2
}
1 }
2
2 /**
2 * Se ejecuta automticamente por el Engine en cada frame del juego
3 * @param DeltaSeconds la diferencia en segundos entre el frame
pasado y el actual
2 */
4 void AHeroCharacter::Tick(float DeltaSeconds)
2 {
Super::Tick(DeltaSeconds);
5
2
//En cada update del juego llamamos al CollectCoins para estar
6
constantemente determinando si se est colisionando con alguna
2 moneda
7
CollectCoins();
2 }
8

2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
Este mtodo como dijimos es el que se llamar constantemente en el Tick del player
para determinar si se est colisionando con una moneda o no. Tomate unos minutos en
los comentarios de cada lnea para que entiendas bien el proceso para determinar si se
est colisionando con una moneda. Este es un mecanismo de colisin muy simple, pero
suficiente para nuestro primer trabajo con colisiones en Unreal Engine 4 :). Una cosa
importante, dentro del mtodo CollectCoins hacemos referencia a la clase ACoin que
creamos, para que esto no de error ve a la parte de arriba del .ccp y debajo de la lnea
#include UE4Demo.h agrega #include Coin.h
Solo nos falta un detallito. Si intentas compilar ahora tendrs un error, porque cuando se
detecta una colisin se llama al mtodo OnCollected de la clase Coin, y nosotros nunca
hemos implementado ese mtodo. Pues bien, vamos a implementarlo.
Agrega la declaracin del mtodo en el Coin.h y la implementacin en el .cpp
1
2
3
4
5
6
7
8
9
1

/** A llamar cuando se detecte la colision con una moneda */


void ACoin::OnCollected()
{
//A modo de Debug ponemos un log en la pantalla
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin
Collected !!");
//Pasamos a false el flag de bIsActive
bIsActive = false;
//Y con el mtodo Destroy de Actor, eliminamos la moneda del
escenario

0
11
1 }
2

Destroy();

Este mtodo es el que se llamar cuando el personaje colisiona con la moneda, y de


momento es muy simple. Primero usamos el mtodo AddOnScreenDebugMessage del
objeto GEngine que nos da el Framework. Este mtodo es muy til porque nos permite
imprimir en la pantalla mensajes de un color determinado por un tiempo determinado.
Para ir revisando nuestro cdigo en tiempo de ejecucin es genial. Aqu lo usamos para
cuando el personaje colisione con una moneda se imprime en pantalla el texto Coin
Collected !!. Adems ponemos en false la moneda y la eliminamos del escenario con la
ayuda del mtodo Destroy() de la clase Actor.
Listo, compila y ejecuta el juego. Ahora camina hacia una moneda Bieeen !! al
pasarle por arriba a la moneda esta se elimina de la escena, se incrementa la cantidad de
monedas colectadas por el personaje (esto es interno, de momento visualmente no
mostramos nada al respecto) y por ultimo mostramos ese log temporal en la pantalla de
Coin Collected !.
Debugueando las colisiones en el escenario
Si le prestas atencin a los detalles vers un problemita que tenemos en este mecanismo
de colisin. Trata de acercarte poco a poco a la moneda, vers que la colisin se detecta
antes de que el personaje est sobre la moneda. Para encontrar el problema en estos
casos el Unreal Engine nos brinda un comando fenomenal que nos permite revisar en
tiempo de ejecucin el componente que tiene cada actor para las colisiones. Dale Play al
juego nuevamente y fjate que el editor tiene en la esquina superior derecha un campo
para escribir comandos. Escribe en ese campo: show COLLISION y toca Enter.
Inmediatamente en el juego se ve sobre cada actor los componentes.

Juego corriendo con el comando show COLLISION para debuguear los componentes
para colisiones de cada Actor.

Fjate que el componente de la moneda es mucho mayor que el modelo de la moneda y


probablemente sea bueno tambin reducir el radio de la capsula del personaje. Termina
la ejecucin del juego, abre el CoinBlueprint, selecciona en el modo Componentes el
ROOT, en el panel Detalles busca la seccin Shape que tiene la propiedad del radio de
la esfera. Cambia este valor a 15, vers como en el preview la esfera que rodea a la
moneda se acopla mucho ms a nuestro modelo. Guarda y prueba de nuevo, vers como
mejor y ahora tiene el personaje que pegarse mucho ms a la moneda para atraparla.

Modificando el radio del componente esfera para ajustar las colisiones con la moneda

Puedes hacer lo mismo para la capsula del personaje si la quieres modificar un poco.
Vale aclarar tambin que estos valores los puedes definir desde un inicio en el
constructor de la clase desde C++. Prueba hacerlo como ejercicio.
Haciendo rotar las monedas constantemente en su eje.
Para darle un poco de vida a las monedas en el escenario, vamos a hacer que estas estn
rotando siempre en el eje Y. Cierra el editor, abre la clase Coin.h y agrega las siguientes
declaraciones:
1/** Factor de rotacion de la moneda */
2UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rotation")
3FRotator RotationRate;
4
5virtual void Tick(float DeltaTime) OVERRIDE;
Simplemente agregamos la declaracin del mtodo Tick que ya conocemos y un atributo
nuevo RotationRate de tipo FRotator. Este ser el vector de rotacin que usaremos para
aplicarle a la moneda constantemente en cada Tick. En realidad no tenemos que declarar

un atributo para esto, pero hacindalo as y sobre todo gracias al macro UPROPERTY
podemos dejar en configuracin desde el Editor el factor de rotacin que tendr la
moneda.
Pasa ahora a Coin.cpp, antes de terminar la implementacin del constructor agrega estas
dos lnea
1//Inicializa el factor de rotacion de la moneda en cada update
2RotationRate = FRotator(0.0f, 180.0f, 0.0f);
3//Activa para que se llame el mtodo Tick de este actor en cada
4update del juego
5PrimaryActorTick.bCanEverTick = true;
La primera es la inicializacin del vector de rotacin que usaremos en el Tick de la
moneda y la segunda lnea es muy importante. Por defecto en esta clase que hereda de
Actor el mtodo Tick NO se llama, para activar en el Engine que se llame el tick de esta
clase es necesario inicializar el atributo PrimaryActorTick.bCanEverTick en true.
Bien, hecho esto agrega la implementacin del mtodo Tick
1void ACoin::Tick(float DeltaTime)
2{
Super::Tick(DeltaTime);
3
4
//Agrega una rotacion a la moneda en cada tick para tenerlas
5rotando constantemente en el escenario
6
AddActorLocalRotation(this->RotationRate * DeltaTime, false);
7}
Como vez, muy simple. Bsicamente en cada update de este Actor lo que hacemos es
agregar un factor de rotacin gracias al mtodo AddActorLocalRotation.
Listo !! compila ejecuta y prueba. Super verdad !! ya las monedas se encuentran rotando
en el escenario esperando a que las atrapes :)
Implementando la lgica de la moneda mediante el Blueprint.
Como ya hemos dicho, la decisin de implementar una determinada cosa en C++ o
mediante VisualScripting con el Blueprint Editor es de uno. Yo en lo personal sigo las
dos siguientes premisas. Primero, implementar algo siempre en un solo lugar. O sea, no
tener parte de la lgica de un Actor en C++ y otra parte en el Blueprint. Trato de tenerlo
todo en un mismo lugar en la medida de lo posible. Segundo, si la lgica a implementar
en determinado Actor es muy simple, como es el caso de esta moneda, pues la solucin
ideal es el Blueprint. Independientemente de que con el Blueprint se pueden
implementar algoritmos sper largos y muy complejos, yo para estos casos prefiero usar
C++.
Una buen ejercicio es que intentes implementar la lgica de la moneda, todo lo que
hemos hecho aqu pero en Blueprint. Te tiene que quedar as:

VisualScript de la moneda

Fjate que desde el Blueprint implementamos lo que va a pasar cuando se llama el


mtodo OnCollected. Para poderlo agregar aqu tienes que agregar en la declaracin del
mtodo el macro UFUNCTION(BlueprintNativeEvent) o
UFUNCTION(BlueprintImplementableEvent). Te explico ambos:
UFUNCTION(BlueprintImplementableEvent) es un mtodo que NO va a tener
implementacin en C++, solamente ser para agregarlo al Blueprint e implementarlo
desde ah. Por lo que en el .cpp no tendrs nada de este mtodo y en el .h solo la
declaracin. Es en el Blueprint donde tienes que implementar lo que har el mtodo.
UFUNCTION(BlueprintImplementableEvent). Este es un poco ms interesante.
Cuando creamos un mtodo con este macro, en la implementacin tenemos que agregar
en el nombre del mtodo _Implementation. Por ejemplo, si quieres probar con
OnCollected. La definicin sera de la siguiente forma:
1 UFUNCTION(BlueprintNativeEvent)
2 void OnCollected();
Y la implementacin quedara as:
1 void ACoin::OnCollected_Implementation()
2 {
//A modo de Debug ponemos un log en la pantalla
3
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin
4 Collected !!");
5
//Pasamos a false el flag de bIsActive
6

7
bIsActive = false;
8
9
//Y con el mtodo Destroy de Actor, eliminamos la moneda del
1 escenario
Destroy();
0
}
11
Lo bueno con esto es que desde C++ tenemos una implementacin, pero si queremos
podemos sobreescribir esta implementacin desde el Blueprint super verdad !??
cosas del UE4 :). Prueba esto implementado toda la lgica de la moneda desde
VisualScripting, para que vayas ganando soltura con el Blueprint Editor, una de las
maravillas del Unreal Engine 4.
Conclusin
Bueno, vamos terminando por hoy con este segundo tutorial sobre el desarrollo de
juegos con Unreal Engine 4. Hoy aprendimos varias: Un mecanismo simple de
deteccin de colisiones, la utilidad del mtodo Tick, le agregamos las acciones de correr
y saltar al personaje, configuramos la cmara de nuestro juego al estilo Side-Scroller
3D, vimos varios macros de variables y funciones de clase para la integracin entre el
cdigo C++ y el Editor, y otras cosillas. Para el prximo tutorial continuaremos nuestro
juego, vamos a agregar un HUD para que el usuario sepa la cantidad de monedas que ha
alcanzado y el tiempo que le queda para lograr su objetivo, vamos a programar el
GameMode para definir las condiciones de GameOver del juego y muchas cosas ms ;)
Espero que te haya sido til y te guste, si es as, djame saber tus comentarios y
comparte este tutorial con el resto de tus amigos tambin apasionados por el desarrollo
de video juegos con Unreal Engine 4. Hasta la prxima !! . . . bye

Introduccin a la Inteligencia Artificial en Unreal


Engine 4
2014/10/11 por nan2cc 5 comentarios
Hola de nuevo, aqu estamos con una nueva entrega de esta serie de tutoriales sobre el
desarrollo de juegos en Unreal Engine 4. En el tutorial pasado comentaba que este
prximo sera sobre el HUD y el GameMode, pero un amigo de MicropsiaGames,
Marco Antonio, que dicho sea de paso, te recomiendo que no te pierdas su juego
INFOCUS Extreme Bike, me coment que sera genial si el prximo tutorial lo haca
sobre IA, y la verdad es que no tuvo que insistir mucho :)
En este tutorial vamos a agregar un enemigo que estar patrullando una zona del nivel.
Cuando nos acerquemos a esa zona y el enemigo se de cuenta que estamos cerca, nos
perseguir, si pierde nuestro rastro volver a su tarea de vigilante. Con este simple

ejemplo veremos varios conceptos relacionados con la inteligencia artificial en Unreal


Engine 4 como el Behavior Tree, Decorators, Task, Services, BlackBoard, AIController
etc.
Manos a la obra !!
Modificando el nivel, la cmara y los controles, a un estilo top-down para analizar
mejor la AI del enemigo.
Antes de comenzar con lo nuevo, vamos a hacer algunas modificaciones en el nivel, el
estilo de cmara y los controles de nuestro juego, para poder analizar mejor el
comportamiento del enemigo y el funcionamiento de la AI que implementaremos.
Vamos a cambiar la cmara del side-scroller a una cmara top-down. Si has seguido los
tutoriales anteriores, seguro que podrs hacer esto por tu cuenta, de todas formas, aqu
te dejo lo que tienes que hacer.
Abre la clase HeroCharacter.h y agrega las declaraciones de los siguientes mtodos:
1 /**
2 * Inicializa las variables SpringArm y SideViewCamera con la
configuracion necesaria

3
4

* para una vista side-scroller


*/

5 void InitSideScrollerCamera(const class


6

FPostConstructInitializeProperties& PCIP);

7
8

/**
* Inicializa las variables SpringArm y SideViewCamera con la

9 configuracion necesaria

1 * para una vista topdown


0
*/

1
void InitTopDownCamera(const class FPostConstructInitializeProperties&
1
PCIP);

1
2
/**

1
3 *

Se llama cuando se detecta la entrada de tipo MoveForward (W o

S).

1
4 *

Determina la direccin en la que est el personaje y le aplica un

1
5
movimiento (positivo o negativo) en esa direccin

1
6 *

1 * @param Value es igual a 1 cuando se detecta W y -1 cuando se


7 detecta S
1 */
8 void MoveForward(float Value);
1
9

Ahora pasa a la .cpp, modifica el constructor y agrega las siguientes implementaciones.


1 AHeroCharacter::AHeroCharacter(const class
FPostConstructInitializeProperties& PCIP)

2
3
4
5
6
7

: Super(PCIP)
{
//Por defecto esta propiedad viene en true para el Character.
//Pero en nuestro modelo de desplazamiento, no queremos que el
personaje rote en base a la rotacin del Controller.
bUseControllerRotationYaw = false;

8
9

//Configuracin del componente CharacterMovement

10
//Al estar en true habilita para que el character se rote en la

11 direccin del movimiento al comenzar el movimiento.


12

CharacterMovement->bOrientRotationToMovement = true;

13
14

//Factor de rotacin para la propiedad anterior.

15

CharacterMovement->RotationRate = FRotator(0.0f, 540.0f, 0.0f);

16
17
18
19

//Bajamos un poco el valor por defecto de MaxWalkSpeed para que


el personaje camine un poco ms lento.
CharacterMovement->MaxWalkSpeed = 400.0f;

20
21
22

//Inicializa SpringArm y SideViewCamera para una vista de juego


estilo side-scroller
//InitSideScrollerCamera(PCIP);

23
24

//Inicializa SpringArm y SideViewCamera para una vista de juego


estilo
top-down
25
InitTopDownCamera(PCIP);

26
27

CoinsCollected = 0;

28
29

30
/** Inicializa SpringArm y SideViewCamera para una vista de juego

31 estilo side-scroller */

32 void AHeroCharacter::InitSideScrollerCamera(const class


33
34
35

FPostConstructInitializeProperties& PCIP)
{
//Inicializando la instancia del USpringArmComponent

SpringArm =
PCIP.CreateDefaultSubobject<USpringArmComponent>(this,
36
TEXT("CameraBoom"));\

37
38

//Agregando el springArm al RootComponent del Character (la

39 capsula de colisin)
40

SpringArm->AttachTo(RootComponent);

41
42
43
44

//bAbsoluteRotation nos permite definir si este apoyo para la


cmara rotar junto con el player.
//En este caso no queremos que rote junto al character
SpringArm->bAbsoluteRotation = true;

45
46
47

//La distancia entre el brazo y su objetivo. Este valor es el


que define la distancia de la cmara.

48

//Prueba con distintos valores para que veas el resultado.

49

SpringArm->TargetArmLength = 500.f;

50
51

//Offset que tendr el Socket.

52

//Un Socket es un punto de anclaje para otros componentes.


//Por ejemplo, para el caso de un personaje podemos definir que

53 tenga un socket en la zona de la mano


54
55

//de esta forma le podemos agregar otro componente (como un


arma, por ejemplo) en la mano
//En nuestro SpringArm, en este socket es donde se agregar la

56 cmara
57

SpringArm->SocketOffset = FVector(0.f,0.f,75.f);

58
59
60

//La rotacin relativa que tendr este brazo con respecto al


padre.
//En este caso queremos que este rotada en el eje Y 180 grados

61 para que quede paralela al character a su mismo nivel.


62
63

//De esta forma logramos el clsico estilo de cmara en los


side-scrollers
SpringArm->RelativeRotation = FRotator(0.f,180.f,0.f);

64
65

// Creando la intancia del tipo UCameraComponent

66

SideViewCamera =
PCIP.CreateDefaultSubobject<UCameraComponent>(this,
67
TEXT("SideViewCamera"));

68
69

//El mtodo AttachTo nos permite agregar un objeto a otro objeto


70 en un socket determinado. Recibe dos parmetros.

71
72
73

//el primero, el objeto al que vamos a anclarnos, en este


el springArm y el nombre del socket donde lo vamos a anclar

//SocketName de USpringArmComponent retorna el nombre del Socket


de este componente.
SideViewCamera->AttachTo(SpringArm,

74 USpringArmComponent::SocketName);
75

caso

76 }
77
78 /** Inicializa SpringArm y SideViewCamera para una vista de juego
estilo top-down */

79

void AHeroCharacter::InitTopDownCamera(const class


80 FPostConstructInitializeProperties& PCIP)

81 {
CharacterMovement->bConstrainToPlane = true;

82

CharacterMovement->bSnapToPlaneAtStart = true;

83
84

SpringArm =

85 PCIP.CreateDefaultSubobject<USpringArmComponent>(this,
86

TEXT("CameraBoom"));
SpringArm->AttachTo(RootComponent);

87

SpringArm->bAbsoluteRotation = true;

88

SpringArm->TargetArmLength = 800.f;

89

SpringArm->RelativeRotation = FRotator(-60.f, 0.f, 0.f);

90

SpringArm->bDoCollisionTest = false;

91
92

SideViewCamera =
93 PCIP.CreateDefaultSubobject<UCameraComponent>(this,
TEXT("TopDownCamera"));

94
95

SideViewCamera->AttachTo(SpringArm,
USpringArmComponent::SocketName);
SideViewCamera->bUseControllerViewRotation = false;

96
97

98
99

/**
*

10 S).
0

Se llama cuando se detecta la entrada de tipo MoveForward (W o

* Determina la direccin en la que est el personaje y le aplica


un
movimiento (positivo o negativo) en esa direccin
10

10 *
2

@param Value es igual a 1 cuando se detecta W y -1 cuando se

10 detecta S
3
*/

10 void AHeroCharacter::MoveForward(float Value)


4
10
5

{
if ((Controller != NULL) && (Value != 0.0f))
{

10
6

//Determina la direccin del movimiento hacia delante

10
7

const FRotator Rotation = Controller->GetControlRotation();


const FRotator YawRotation(0, Rotation.Yaw, 0);

10
8
10
9
11
0
11
1

// Crea el vector de la direccin y aplica el movimiento


const FVector Direction =
FRotationMatrix(Rotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}

11
2
/**

11
3 *

Se llama cuando se detecta la entrada de tipo MoveForward (A o

D).

11
4 *

@param Value Value es igual a 1 cuando se detecta D y -1 cuando


se detecta A

11
*/
5
void AHeroCharacter::MoveRight(float Value)

11
6 {
11
7
11
8
11
9
12
0

if ( (Controller != NULL) && (Value != 0.0f) )


{
//Determina la direccin del movimiento hacia los lados
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);

// Crea el vector de la direccin y aplica el movimiento

12
1

const FVector Direction =


FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
}

Fjate que aqu tambin modificamos la implementacin del mtodo MoveRight.


Comenta la actual implementacin y deja esta, para que el control del personaje se
ajuste al estilo de cmara.
No vamos a detenernos aqu, porque, como te deca, si has seguido los tutoriales
anteriores no tendrs problema con lo que hemos hecho. Bsicamente creamos dos
mtodos distintos para inicializar los objetos SpringArm y SideViewCamera segn el
estilo que queramos. Dale una revisin al mtodo InitTopDownCamera que es el que
usaremos ahora y que configura el SpringArm para un estilo top-down, nada del otro
mundo, de hecho el cdigo fue copiado del proyecto base top-down que brinda el UE4
:).
Adems de esto, agregamos la declaracin del mtodo MoveForward que usamos en el
primer tutorial, ya que vamos a modificar el estilo de juego para que el personaje se
mueva libremente por todo el mundo 3D y hacer un poco ms compleja la
implementacin de la AI del enemigo :).
Po ltimo agrega al mtodo SetupPlayerInputComponent la lnea siguiente
InputComponent->BindAxis("MoveForward", this,

1&AHeroCharacter::MoveForward);

Fjate que para regresar a la implementacin de la cmara al estilo side-scroller solo


tenemos que eliminar la llamada en el constructor del HeroCharacter al mtodo
InitTopDownCamera y en cambio llamar al mtodo InitSideScrollerCamera, regresar a
la implementacin del MoveRight que tenamos anteriormente y eliminar la entrada del
MoveForward en el SetupPlayerInputComponent.
Compila y abre el Editor. Agrega un nuevo Input de nombre MoveForward para las
teclas W y S como hicimos en el primer tutorial.
Modifica un poco el nivel, copiando el objeto Floor y usando las herramientas de
Transformacin para crear una plataforma que ser la que estar patrullando el enemigo.
A pesar que en el estilo final de nuestro juego no es necesario que la plataforma tenga
mucho espacio hacia atrs, para este ejemplo crsela tambin en ese eje, con el objetivo
de crear un buen espacio para que el enemigo se desplace libremente y poder probar y
jugar mejor con la AI.

Por ltimo, tenemos que encerrar la zona que va a patrullar el enemigo con un objeto de
tipo NevMeshBoundsVolume. Arrastra al nivel, desde la seccin Volumes, un Nav Mesh
Bounds Volume y modifcalo para que encierre todo el nivel. A mi me qued as:

Creado el enemigo a partir de un AIController


En el primer tutorial explicamos la filosofa que segua el framework de UE4 en su
jerarqua de clases en lo referente a los personajes de nuestro juego, hablamos que el
personaje principal era un Pawn especial, un Character, y este era controlado por el
PlayerController. Los personajes que usan inteligencia artificia, generalmente
conocimos como non-player characters (NPC), como los enemigos por ejemplo,
funcionan muy parecidos, su representacin en el juego es mediante un Pawn y tambin
son controlados por un Controller, pero en este caso por un AIController.
Por lo dems, bsicamente contienen lo mismo que nuestro personaje principal. Un
skeletal mesh, el sistema de animaciones, el Movement Component etc. Para nuestro
ejemplo, haremos al enemigo a partir de las mismas animaciones y modelo de nuestro
personaje protagnico, aunque si quieres variar te recomiendo de nuevo que te des una
vuelta por el Marketplace, ah podrs encontrar varios modelos de personajes con sus
animaciones listos para usar y muchsimo ms cool que los que estamos usando y
GRATIS ;)
Crea una carpeta en el Content Browser, ponle el nombre que quieras, en mi caso le
puse AIEnemy.
Crea dentro de esa carpeta un nuevo Blueprint que herede de AIController y ponle de
nombre AIEnemyController. Crea otro Blueprint que herede de Character y ponle de
nombre AIEnemyCharacter. Ahora vamos a configurar el Skeletal Mesh y las

animaciones para el enemigo, que como dijimos, usaremos las mismas animaciones y el
mismo mesh que el personaje principal. Da doble clic en AIEnemyCharacter, seccin
Componentes, selecciona el componente Mesh y en la seccin Mesh para el atributo
Skeletal Mesh selecciona el mismo Mesh que estamos usando para nuestro personaje
protagnico y ajstalo dentro de la capsula como ya hemos hecho antes. En la seccin
Animation selecciona para el atributo Anim Blueprint Generated Class la misma que
estamos usando para nuestro personaje. Selecciona el Capsule Component y cambia el
atributo Capsule Half Height a 96 y Capsule Radius a 42. Esto es para ajustar un poco la
capsula al modelo.
Selecciona el componente CharacterMovement y en la seccin Movement Component
despliega Nav Agent Props en el atributo Agent Radius ponle 42 (este atributo tiene que
ser al menos del tamao del radio de la capsula) y el atributo Agent Height ponlo en 192
(este tiene que ser al menos el doble del atributo Capsule Half Height). La propiedad
NavAgentProps define como el sistema de navegacin del NPC interacta con este
componente.
Ahora pasa al Max Walk Speed y ponle 400.
Por ltimo, pasa al modo Defaults y en la seccin AI, para el atributo AIControllerClass,
selecciona el AIController que acabamos de crear, AIEnemyController. Con esto le
decimos al AICharacter que ser controlado por el AIEnemyController.
A diferencia de como hicimos con nuestro personaje, vamos a configurar a nuestro
enemigo COMPLETAMENTE desde el Editor mediante el Blueprint. Aunque en un
prximo tutorial veremos la variante de hacerlo desde C++ para que tu solo tomes la
decisin de la variante que prefieres.
Ahora agrega el AIEnemyCharacter al nivel en la zona que creamos con bastante
espacio. Guarda y corre el juego. Muvete hasta la zona donde pusimos al enemigo,
como vers, ya lo tenemos ah, pero est parado sin hacer nada, y aunque nos
acerquemos a l, ni se inmuta :(. Vamos a arreglar esto, vamos a darle vida.

Un poco de teora sobre la inteligencia artificial en Unreal Engine 4 y el Behavior


Tree
En UE4 hay muchas formas de implementar la lgica de un personaje AI, una muy
simple es en el mismo Blueprint del Character, haciendo uso del evento Tick,
implementar algn algoritmo para que el personaje se mueva de un lado a otro, que
compruebe que est cerca de alguien con los mtodos que brinda el Engine (y que
veremos algunos hoy) y nos ataque o haga cualquier otra cosa. Esto se puede
implementar directamente ah, pero a medida que necesitemos complejizar las acciones
que tendr ese Actor, los estados en los que podr estar y las cosas que podr hacer en
cada situacin, se har mucho ms complejo el control y el mantenimiento de toda esa
lgica, ya sea en VisualScript o desde C++.
Este es uno de los motivos por los que el UE4 nos facilita la creacin de un Behavior
Tree (rbol de comportamiento) para poder definir el comportamiento que tendr el
NPC segn las condiciones en las que se encuentre. Behavior Tree es un concepto de
mucho tiempo de la IA que no vamos a detenernos en l aqu, si quieres profundizar en
la teora detrs de los arboles de comportamientos para mecanismos IA puedes poner en
Google behavior tree ai y date una vuelta por el resultado que ms te llame la atencin
;)
Creando el Behavior Tree y el BlackBoard que definir el comportamiento del
enemigo
Despus de est teora vamos a la prctica. Entra en la carpeta AIEnemy en el Content
Browser y selecciona New/Miscellaneous/Behavior Tree ponle de nombre
AIEnemyBehaviorTree y New/Miscellaneous/Blackboard y ponle de nombre
AIEnemyBlackboard

En el objeto Behavior Tree mediante el Blueprint vamos a disear de forma visual todo
el rbol de comportamiento del personaje y el Blackboard es la fuente de
conocimiento de nuestro personaje AI, o sea, todas las variables globales que necesite
el personaje para poder definir su comportamiento las definiremos aqu y los nodos que
tenga nuestro rbol y necesiten esta informacin, harn referencia a ella mediante los
mtodos Get Blackboard Key As o Set Black Board Key As. Por ejemplo, una variable
que define una parte del comportamiento del personaje es la referencia al actor que tiene
que perseguir si lo ve. Pues en este caso, esa variable o ese conocimiento que necesita
el personaje la tenemos que definir aqu.
Un detalle a aclarar es que en el Blackboard lo que definimos en realidad son parejas de
clave-valor donde el valor ser del tipo de dato del que definimos para la clave.
Enemigo patrullando una zona del nivel
Vamos con la primera tarea que tiene el enemigo, patrullar una zona del nivel. Primero,
pensemos cual es la lgica detrs de alguien que est vigilando un lugar ? Simple,
estar caminando de un lado hacia el otro, en cada punto crtico se detendr unos
segundos y pasar al siguiente, y as en ciclo infinito (a menos que se canse y se quede
dormido :) . )
En el modelo side-scroller que estamos usando en nuestro juego esto es muy simple
porque como todo el desplazamiento se hace en un solo eje, bsicamente el enemigo se
estara moviendo de un lado al otro y nada ms. Por este motivo es que cambiamos el
estilo de nuestro juego temporalmente, para complicar un poco el movimiento que tiene
que tener el enemigo y hacer ms interesante nuestro estudio ;). Vamos a hacer que este
enemigo est caminando por 4 puntos clave del nivel. Se mover al primero, cuando
llegue se detendr unos segundos, pasar para el segundo, se volver a detener y as
Vamos primero a crear los objetos que agregaremos al nivel y usaremos como puntos
clave en el camino. En estos puntos es donde se detendr el personaje antes de pasar al
siguiente y definirn la trayectoria que patrullar. En el Content Browser crea un nuevo
Blueprint que herede de TargetPoint dale de nombre AIEnemyTargetPoint. TargetPoint
es un simple Actor con una imagen que lo identifica en el Editor cuando lo agregamos al
nivel, esta imagen no se ve en el juego, solo en el editor. Dale doble clic y crale una
variable int de nombre Position y mrcale el iconito del ojito que tiene a la derecha de la
variable para hacerla pblica. Esto nos permite acceder al contenido de esta variable
desde un blueprint externo a ella, el mismo concepto de un atributo publico en
programacin orientada a objetos. De hecho, es exactamente esto, AIEnemyTargetPoint
es una clase que hereda de TargetPoint y que tiene un atributo pblico de nombre
position y tipo int. En este atributo vamos a tener el orden, por llamarlo de alguna
manera, que tiene que seguir el personaje en su recorrido.

Agrega al nivel cuatro AIEnemyTargetPoints y distribyelos en el escenario por


distintos puntos, definiendo el camino que quieres que recorra el personaje.
Ahora ve seleccionando uno a uno y en el panel de propiedades vers en la seccin
Default la variable Position, ve por cada uno y ponle 0, 1, 2, y 3. La idea es que el
personaje comience en el punto 0, despus se mueva el 1, despus al 2, despus al 3 y
despus de nuevo al 0. A mi me qued as:

Muy bien, ya tenemos listo al enemigo y tambin los puntos que definen el camino que
tendr que patrullar, ahora solo falta implementarle la inteligencia para que se mueva
de un punto a otro en ciclo y esto lo haremos mediante el Behavior Tree y sus
componentes. Vamos a agregarle las primeras ramas al rbol de comportamiento de
nuestro personaje.
Antes, djame comentarte en general cual sera la lgica que seguir ese personaje para
lograr su comportamiento. En el nivel tenemos 4 puntos que marcan el recorrido, el
personaje necesita saber en que punto est actualmente del recorrido y la posicin de ese
punto en el espacio (vector 3D). Una vez que registre al punto al que se va a mover, que
actualice su siguiente punto. Cuando termine el movimiento que espere unos segundos
en la zona y pase al siguiente punto.
Abre el BT que creamos y en el en el panel de Detalles en la seccin BT selecciona para
el atributo Blackboard Asset el Blackboard que acabamos de crear. Ahora abre el
Blackboard y vamos a agregar a este los pares Clave-Valor que necesitamos. Da clic en
el botn de agregar nueva variable y ponle de key TargetPointNumber de tipo de dato
int. Crea otra clave y ponle TargetPointPosition de tipo de dato Vector. En la primera
vamos a guardar el punto al que se tiene que dirigir el personaje y en
TargetPointPosition vamos a tener la posicin de ese punto para poderle decir despus
que se mueve hacia ah.

Ahora vamos a crear el primer Nodo de nuestro BT. Crea un nuevo Blueprint en el
Content Browser que herede de BTTask_BlueprintBase y ponle de nombre
UpdateNextTargetPointTask. BTTask_BlueprintBase es la clase que nos brinda el UE4
para los nodos de tipo Task del BT y que se van a usar mediante el Blueprint.
Los nodos Task sern las hojas del rbol (los nodos que no tienen hijos) y su objetivo es
ejecutar una accin determinada. Este Task que acabamos de crear lo que har ser
comprobar el valor que tiene la clave TargetPointNumber en el Blackboard y validar
que si es mayor igual que 4 la reinicia a 0 para que del cuarto punto pase de nuevo al
primero. Obtendr la posicin en el espacio del TargetPoint al que le toca moverse y
settear el valor de la entrada TargetPointPosition del Blackboard, para que en otro Task
se ejecute la accin de moverse a ese punto. Esto se pudiera hacer en este mismo Task,
pero vimos que uno de los objetivos ms claros que tiene el BT es separar las acciones
en subacciones concretas. Por lo que para esta tarea de patrullar en general la zona
tendremos tres Task que sern nodos hijos de una secuencia.

Dale doble clic al Task que acabas de crear y agrega dos variables TargetPointNumber y
TargetPointPosition ambas de tipo BlackboardKeySelector. Ahora comienza a agregar
nodos y hacer conexiones hasta que el rbol te quede como el siguiente:

no voy a ir paso a paso en como tienes que hacer esto, porque si has seguido los
tutoriales anteriores lo tienes que saber hacer. Por supuesto, s vamos a explicar la lgica
que sigue el algoritmo.
Comenzamos el algoritmo cuando se dispara el Evento Execute del Task, lo primero que
hacemos es comprobar que el valor que est registrado en el TargetPointNumber del
BlackBoard sea mayor que 4. Recuerda, en esa variable tenemos el Position del
TargetPoint al que tiene que moverse el personaje, por lo que tenemos que comprobar
que si llega al ltimo reinicie su valor al primero. Para obtener el valor de una variable
que tenemos en el BlackBoard se usa el nodo GetBlackBoard As [Tipo de dato], en este
caso int y le tenemos que decir cual es el Key que vamos a modificar y es para esto que
creamos las dos variables al inicio de tipo BlackBoardKeySelector.
Una vez que tenemos el Position del TargetPoint al que le toca ir al NPC vamos a
buscarlo en el nivel. Para esto usamos el Nodo Get All Actors of Class que le podemos
definir en el puerto Actor Class el tipo de clase que queremos obtener, aqu
seleccionamos AIEnemyTargetPoint y nos retornar en el puerto de salida un arreglo
con todos los actores que hay en el nivel de tipo AIEnemyTargetPoint.
Despus recorremos este arreglo con el nodo ForEach, tenemos que castear cada
elemento del ciclo a AIEnemyTargetPoint y eso lo hacemos con la ayuda del nodo Cast
To AIEnemyTargetPoint, dentro del ciclo preguntamos en cada iteracin si la propiedad
Position (que creamos como publica en el Blueprint del AIEnemyTargetPoint) es igual
al valor que tenemos registrado en el TargetPointNumber del BlackBoard, y si es igual
obtenemos la posicin en el espacio de ese actor y seteamos el valor del otro Key que
tenemos en el Blackboard, el TargetPointPosition para almacenar ah el vector con la
posicin del siguiente TargetPoint al que se mover el enemigo en su recorrido.
Por ltimo, como dijimos, los Task tiene que terminar de dos formas: con xito o con
Fallo. Segn la forma en la que termine definir el comportamiento de su nodo padre.
En este caso, como todo el proceso lo tendremos dentro de un Sequence, necesitamos
que termine en xito para que el nodo Sequence siga ejecutando al siguiente nodo.

Fjate que al salir del puerto Completed del ForEach, el que se ejecuta cuando termina el
ciclo, incrementamos primero el valor del TargetPositionNumber, para que la prxima
vez que se ejecute este Task se obtenga la posicin del siguiente TargetPoint en el nivel.
Por ltimo terminamos la ejecucin del Task con el nodo FinishExecute, asegrate de
marcar el puerto Success. Guarda y compila.
Ahora solo queda configurar el Behavior Tree con este Task. Abre el
AIEnemyBehaviorTree. Inicialmente solo tenemos un nodo, el nodo raz del rbol.
Arrastra desde el borde inferior del nodo Root y conecta a este un nodo Sequence, este
nodo los usaremos cuando queramos ejecutar un grupo de Task en secuencia, una detrs
de la otra, comenzando por la izquierda, siempre ten en cuenta que para que se ejecute
el siguiente Task, el anterior tiene que haber retornado con xito.
Arrastra del borde inferior del nodo Sequence y agrega el Task
UpdateNextTargetPointTask, selecciona el nodo y en el panel de detalles en la seccin
Default, el campo Target Point Number seleccinale la opcin TargetPointNumber y en
Target Point Position selecciona la opcin Target PointPosition. Estos combos lo que
listan son todos los keys que tenemos registrado en el Blackboard, lo que estamos
haciendo es definiendo que esas dos variables que tenemos en el Task representan esos
Keys del Blackboard
Un momento sin tener que correr te dars cuenta que con esto no es suficiente,
porque lo que hace el Task es solamente darle valor a las variables TargetPointPosition y
TargetPointNumber y ms nada. Arrastra del borde inferior del Sequence y agrega el
Task: Move To. Este Task por defecto nos lo brinda UE4 y lo que hace es decirle al
AICharacter que se mueva a una posicin determinada. Selecciona en el panel de
Detalles en la propiedad Blackboard Key la variable TargetPointPosition. Con esto
estamos definiendo cual ser el Key del Blackboard que tendr la posicin a donde se
mover el personaje, est posicin es obtenida en el Task anterior segn el TargetPoint
al que le toque ir al personaje.
Con esto es suficiente, pero si corremos en este punto, el personaje ir caminando
pasando por los 4 puntos sin detenerse, y evidentemente esto har que se canse ms
rpido y se nos quede dormido al momento :S para evitar esto agrega un tercer Task
al sequence, ahora el Task Wait. Este Task, tambin incluido en el UE4 nos permite
detener la ejecucin del rbol un tiempo determinado. En el panel de Detalles en el
atributo Wait Time puedes definir el tiempo que estar detenido, yo puse 2.
Listo !!, el BT te tiene que quedar as.

Es vlido aclarar en este punto un detalle. El Nodo Wait lo que hace es detener
completamente la ejecucin del rbol, por lo que si en este intervalo de tiempo nos
acercamos al personaje, el NPC no nos detectar, ya que todo el rbol est detenido. De
cualquier forma creo que es un ejemplo vlido del uso del Task Wait.
Configurando el AIController para que use el Behavior Tree que define su
comportamiento
Solo nos falta una cosa, s, ya tenemos configurado el Behavior Tree, pero en ningn
lado le hemos dicho al AIController que use este BT para definir su comportamiento.
Para esto, abre el AIEnemyController agrega el nodo Begin Play y conctalo a un nodo
de tipo Run Behavior Tree en el puerto BTAsset selecciona el AIBehaviorTree. Tan
simple como eso.

Compila, ejecuta el juego y muvete hacia el enemigo. Vers como estar rondando de
punto a punto y en cada uno esperar 2 segundos antes de continuar. :) puedes en lo
que est en ejecucin el juego abrir el Behavior Tree para que veas porque rama est el
rbol en cada momento.

Creando un Service en el Behavior Tree para que el personaje est al tanto de


quien se acerque a la zona.
Ya tenemos al enemigo haciendo su recorrido rutinario, pero bastante poco eficiente es
como vigilante no ? . . . por ms que nos acerquemos a la zona, ni se inmuta :(. Vamos
entonces a ensearle a vigilar la zona, o sea, a que detecte cuando nos acerquemos.
Como ya vimos, en el BT, los Task son para ejecutar una accin determinada cuando sea
el momento adecuado y retornar un resultado. Pero en este caso no es exactamente esto
lo que necesitamos, aqu necesitamos ejecutar un proceso constantemente ya que un
buen vigilante tiene que estar atento, contantemente, para saber si alguien se aproxima :)
. Para esto tenemos otro tipo de Nodo en el Behavior Tree, que son los Services. Service
es el nodo que tenemos en el Behavior Tree para tener un proceso ejecutndose
contantemente cada un intervalo de tiempo determinado, y es exactamente este tipo de
nodo el que tenemos que usar para implementarle la tarea de vigilante a nuestro NPC.
En el Content Browser dentro de la carpeta AIEnemy crea un nuevo Blueprint que
herede de BTService_BlueprintBase y ponle de nombre CheckNearbyEnemy. Antes de
editar este Blueprint, tenemos que agregar una nueva entrada en el BlackBoard. Un
nuevo conocimiento que tendr que tener el NPC, y es el actor al que va a seguir
cuando detecte que hay alguien en la zona.

Abre el Blackboard y agrega un nuevo Key de tipo Object y ponle de nombre


TargetActorToFollow. Aqu guardaremos la referencia a nuestro personaje protagnico
cuando nos acercamos a la zona que vigila el enemigo.
Abre el CheckNearbyEnemy y primero crea las siguientes variables que usaremos en
este visualscript:
DesiredObjectTypes de tipo EObjectTypeQuery y en la seccin Default Value del panel
de Detalles de esta variable, selecciona Pawn. En un segundo te explico donde la
usaremos.
TargetActorToFollow: De tipo BlackBoardKeySelector y como ya hicimos en el Task
que creamos, esta variable la usaremos para obtener el valor de la clave con este nombre
en el Blackboard. Esta variable crala pblica dando clic en el iconito del ojito que tiene
a la derecha.
Te explico lo que tiene que hacer el algoritmo para que lo intentes crear por tu cuenta,
de cualquier forma te dejar tambin la imagen de referencia.
Los nodos de tipo Service en el BT cuentan con el evento Event Receive Tick, este
evento es muy parecido al Tick que ya vimos en el tutorial pasado, solo que a diferencia
de ese, este se ejecuta a un intervalo fijo configurable. Lo que vamos ha hacer
constantemente, gracias al evento Tick del Service, es generar una esfera imaginaria
alrededor de todo el NPC mediante el Nodo Multi Sphere Trace for Objects. Este es un
mtodo sper til que nos da el UE4 y nos permite generar un esfera imaginaria en una
posicin determinada con un radio que queramos y obtener todos los objetos que estn
dentro de esa zona de la esfera. Este mtodo espera los siguientes parmetros:
Puntos de Inicio y fin de la lnea que usar como referencia para generar la esfera, en
este caso usamos la posicin del NPC como punto de inicio y el mismo punto en X y Y
pero solo con un poco ms de altura para que sean distintos los puntos (si inicio y fin
son iguales, no funcionar). Usamos la posicin del NPC para que siempre la esfera se
genere alrededor de este personaje.
El parmetro Radio es bastante claro, es el radio de la esfera. Le damos un valor
bastante grande y definir el alcance de vigilancia del enemigo a la redonda.
El parmetro Object Types es un arreglo que define los tipos de objetos que queremos
tener en cuenta para ese chequeo. En este caso queremos tener en cuenta a los objetos
de tipo Pawn. Y para esto fue que creamos la variable DesiredObjectTypes y le dimos el
valor de Pawn por defecto. Fjate que este parmetro es un arreglo, podemos pasarle
ms de un tipo, pero en este caso solo queremos tener en cuenta a los Pawns por eso es
que creamos un arreglo de un solo elemento.

Trace Complex: No necesitamos tenerlo en true, se usa para chequeo en mallas de


colisiones complejas, pero requiere mayor consumo de recursos. Como este no es el
caso de nosotros, lo podemos dejar en false.
Actors To Ignore: Otro muy til parmetro que recibe este mtodo. Nos permite definir
todos los actores que queremos que ignore el mtodo, o sea que aunque estn dentro de
la esfera y sean un Pawn no se van a devolver en el resultado. Y aqu lo usamos para
ignorar el propio Pawn del enemigo. Lgico no ?, el enemigo siempre va a estar dentro
de la esfera pero l no ser un resultado que nos interese.
Draw Debug Line es un muy til parmetro que nos sirve para debugear la esfera en el
nivel. Para esta prueba ponlo en For Duration y podrs ver el comportamiento de esta
esfera imaginaria en el nivel cuando lo probemos.
Cada vez que se ejecute este mtodo como resultado tendremos todos los actores que
estn dentro de la esfera, y por tanto cercanos al enemigo o false si no se encuentra
ninguno. Esto es lo que haremos en la primera parte del algoritmo. Paso a paso sera:
1 Casteamos el Actor que viene en el Tick a AIEnemyController que es el Controller
de nuestro enemigo.
2 Obtenemos el Pawn de ese Controller con el nodo Get Controller Pawn.
3 Obtenemos la posicin del Pawn con el nodo Get Actor Location
4 Creamos u nuevo vector a partir de la posicin del Pawn incrementndole solo en el
eje Z un poco. Estas dos posiciones las pasamos como parmetro al nodo
MultiSphereTrace for Objects. Adems le pasamos los otros parmetros que necesita.
Fjate que la lnea blanca define el flujo de ejecucin del algoritmo.
Una vez que se ejecuta MultiSphereTrace for Objects tenemos en el puerto de salida
Out Hits un arreglo de objetos HitResults y en el puerto Return Value, true, si se
encontr algn objeto y false en caso contrario.
En este punto necesitamos una condicin y para eso usamos el Nodo Branch que recibe
el flujo de ejecucin (los puertos blancos) y permite separar el script en dos flujos segn
el resultado de la condicin, este nodo es el clsico IF de programacin.
Si MultiSphereTrace for Objects retorna true quiere decir que encontr resultados.
Entonces, continuamos el flujo del programa con el nodo ForEachLoopWithBreak, este
nodo como su nombre lo indica, es el clsico for each de C++ que permite iterar un
arreglo de elementos y detenerlo, llamando al break, cuando se cumpla la condicin que
buscamos. Iteramos entonces todos los actores que se encontraron dentro de la esfera.
Fjate que tenemos que conectar el puerto de salida Hits del MultiSphereTrace for

Objects al puerto de entrada Array del ForEachLoopWithBreak para hacerle saber a este
cul es el array que va a iterar.
El puerto Loop Body del ForEachLoopWithBreak es el flujo del programa en cada
iteracin del ciclo, entonces, dentro del ciclo hacemos otro Branch para preguntar si el
Actor que se encontr es el Player y si es as lo guardamos en el Blackboard en el key
TargetActorToFollow. El MultiSphereTrace for Objects lo que retorna es un array de
HitResults esta estructura tiene muchsima informacin del punto de interaccin, no es
solo el actor, por lo que necesitamos el nodo Break Hit Result para obtener el actor, este
nodo en el puerto de salida Hit Actor nos da el Actor. Fjate que para obtener el Pawn
usamos el mtodo Get Player Character que ya hemos usado en los tutoriales anteriores.
Fjate tambin que una vez que setteamos el valor del TargetActorToFollow pasamos el
flujo al Break del ForEach porque ya no necesitamos ms nada.
Bien, este es el caso donde se encuentra al personaje protagnico dentro de la esfera.
Pero para el caso en el que el Actor que se encuentre dentro de la esfera no sea el
personaje protagnico o que el mtodo MultiSphereTrace for Objects retorne false, que
quiere decir que no hay ningn Pawn dentro de la esfera, hay que dejar la variable
TargetActorToFollow en NULL para poder determinar, con otro tipo de nodo del BT
que veremos ahora, si tenemos al personaje protagnico cerca y lo seguimos, o no, y
entonces seguimos con la rutina de vigilancia normal.
Por ltimo, solo para testear, puedes agregar un nodo Print String cuando seteamos el
valor del TargetActorToFollow con el texto Detectado Enemigo cercano. Este nodo
imprime en la pantalla el texto que le indiquemos como parmetro y nos servir aqu
para ver el resultado de nuestro Service en ejecucin
Finalmente, el Blueprint te tendr que quedar as:

Agregando el Service CheckNearbyEnemy al Behavior Tree.


Solo resta agregar este nuevo nodo al BT. Abre el AIEnemyBehaviorTree, elimina el
Link entre el nodo ROOT y el Sequence. Arrastra el borde inferior del ROOT y agrega
un Selector nuevo. Da clic derecho sobre ese nuevo selector/Add Service y selecciona
CheckNearbyEnemy. Se te agregar dentro del Selector. Seleccinalo y en el panel de
Detalles la seccin Default el atributo TargetActorToFollow (que es la variable que le
declaramos al blueprint como pblica) seleccinale como valor TargetActorToFollow
del combo que hace referencia a las variables declaradas en el BlackBoard. Fjate

tambin que en la seccin Service podemos modificar el intervalo del Tick y un


aleatorio de desviacin, para que no siempre se ejecute exactamente en un intervalo fijo.
De momento podemos quedarnos con los valores por defecto.

Guarda y ejecuta el juego. Veras el debug en rojo de la esfera que se ejecuta alrededor
del enemigo. Recuerda que esto es un debug, despus le quitas el valor que le dimos al
parmetro Draw Debug Line y no se ver nada. Ahora camina con el personaje cerca del
enemigo. Inmediatamente que entres dentro del espacio de la esfera, se imprime en la
pantalla el texto Detectado Enemigo Cercano (recuerda agregar ese nodo Print String
al Blueprint para que puedas ver esta salida)

Creando otro Task en el Behavior Tree para perseguir al personaje cuando el


enemigo detecte que est cerca.
Sper hasta ahora verdad !? :) pero seguimos teniendo un enemigo un poco bobo
porque a pesar de ya detectar que nos acercamos a su zona de seguridad, no hace nada,
sigue sin inmutarse. Vamos a solucionar esto, y para ello necesitamos otro Task. Como
dijimos, los Task son para ejecutar acciones concretas y es exactamente eso lo que
queremos. Cuando el enemigo nos detecte, que nos persiga.
Vamos al Content Browser, en la carpeta AIEnemy y crea un nuevo Blueprint que
herede de BTTask_BlueprintBase y dale de nombre MoveToEnemyTask. brelo para
editarlo y agrega la variable TargetActorToFollow de tipo BlackBoardKeySelector y
hazla pblica. Despus crea el siguiente algoritmo.

Que hacemos aqu ?. Iniciamos el algoritmo cuando se lanza el evento Execute del Task,
casteamos el Owner Actor a nuestro AIEnemyController, obtenemos el Pawn del
enemigo y usamos un mtodo SUPER GENIAL que nos da el UE4, el nodo AI Move
To. Con este mtodo podemos indicarle a un NPC que persiga a otro actor deja que
lo veas funcionando !!, parece mentira el poder lograr algo tan complejo con un solo
nodo :)
El nodo AI Move To espera como parmetros el Pawn, un Destino que ser un vector
fijo u otro Actor que ser al que perseguir el Pawn pasado en el primer parmetro. En
este caso usaremos el puerto Target Actor y le pasaremos el actor que est guardado en
el TargetActorToFollow del BlackBoard, que contiene la referencia a nuestro personaje
cuando nos acercamos a la zona de vigilancia del enemigo gracias al Service que
creamos hace unos minutos. Por ltimo, llamamos al Finish Execute cuando el AI Move
To retorna On Success que quiere decir que el enemigo nos alcanz. Fjate que aqu
tambin podemos usar el Print String para ver en pantalla exactamente cuando el
enemigo llega a nosotros.
Creando un Decorator en el Behavior Tree
Espera ! ! ! de seguro que ests loc@ por conectar este Task al rbol y probar, pero
tenemos un pequeo detalle. Este Task solamente lo podemos ejecutar si la variable

TargetActorToFollow tiene valor en el BlackBoard, porque como vimos si el


CheckNearbyEnemy determina que el personaje no est cerca, deja en NULL est
variable y entonces no tiene porqu ejecutarse esta rama del rbol de comportamiento,
sino que pasa a la seccin de vigilante.
Para ejecutar condiciones en el Behavior Tree que determinen si continuar ejecutando
una rama determinada del rbol tenemos otro tipo de nodo que son lo Decorators.
Vamos entonces a crear un decorator para comprobar si la variable est seteada, y si es
as, entonces se puede ejecutar este Task, sino, pasa a la otra rama del rbol.
Arrastra del borde inferior del CheckNearbyEnemy y crea un nuevo Selector, dale clic
derecho y selecciona Add Decorator y selecciona Blackboard. En este caso no vamos a
crear un Decorator personalizado, vamos a usar como mismo usamos el Task Wait y
Move To que ya vienen con el UE4, el decorator Blackboard, que nos permite
comprobar el valor de un key en el BlackBoard. Selecciona el decorator y en la seccin
Flow Control de panel de Detalles, en el atributo Observer aborts selecciona Both. Este
parmetro define como se comportar el rbol cuando no se cumpla la condicin. En
este caso lo que queremos es que inmediatamente que TargetActorToFollow est en
NULL se pase a ejecutar la otra rama, para que contine como vigilante. Prueba
cambiar despus este valor a Self para que notes la diferencia del comportamiento.
En la seccin Blackboard, en el atributo BlackBoard Key, selecciona
TargetActorToFollow para definirle que este es el key del blackboard que queremos
comprobar y en Key Query selecciona Is Set para definirle el tipo de condicin que
queremos comprobar sobre el TargetActorToFollow.
Por ltimo arrastra del selector que tiene este Decorator y conecta el Task
MoveToEnemyTask, seleccinalo y en la seccin Default, en el atributo Target Actor To
Follow selecciona TargetActorToFollow.

Listo !! Guarda, compila y ejecuta el juego y muvete cerca del enemigo, cuando te vea
corre rpido para que te le alejes, vers como inmediatamente que nos alejamos se
incorpora a su tarea rutinaria. Si nos quedamos quietos, y nos alcanza, de momento solo
imprimimos en la pantalla un mensaje. En prximos tutoriales haremos algo ms
interesante.

Conclusin
Espero que este tutorial te sirva para iniciarte en el complejo mundo de la IA en los
juegos desarrollados con Unreal Engine 4. Como has notado es un tema relativamente
complejo, por lo que te recomiendo que le des ms de una pasada al ejercicio, pruebes
distintas cosas, juegua con los valores de retorno de los Tasks para que puedas lograr
buena soltura y entender al 100% como es que funciona esta genial herramienta que nos
da el Unreal Engine 4 para implementar la inteligencia artificial de los NPC en nuestros
juegos.

En el prximo tutorial vamos a continuar con este ejemplo implementado los


mecanismos para que este enemigo nos haga algo cuando llegue a nosotros. Tambin le
dedicaremos un tiempo a ver esta misma implementacin pero desde C++, y as
analizamos las dos variantes ;)
Mientras, me gustara escuchar tus comentarios. Recuerda que puedes estar al tanto de
los siguientes tutoriales siguindome en mi Twitter @nan2cc y si tienes alguna
sugerencia de tema para un prximo tutorial me encantara que me la hagas saber.
Hasta la prxima !!

Introduccin a la IA en UE4 (Variante


en C++)
2014/10/23 por nan2cc Deja un comentario
En Unreal Engine 4 tenemos dos grandes mtodos a la hora de implementar alguna
parte de nuestro juego. La variante en C++ y la variante en VisualScript mediante los
Blueprint. Como ya hemos hablando antes, la decisin de irnos por una va u otra es de
cada cual, con la experiencia, se va logrando soltura a la hora de seleccionar que camino
tomar.
En este tutorial no vamos a implementar ninguna funcionalidad nueva en nuestro juego.
Vamos a implementar las mismas acciones que tiene el NPC del tutorial pasado, pero en
C++. Esto nos va a servir para acercarnos un poco ms al Framework C++ que nos
brinda el Engine. Veremos como incluir nuevos mdulos al proyecto. Cmo iterar por
objetos del nivel. Cmo manipular la informacin guardada en el Blackboard que usa el
AIController desde C++ y cmo crear Task y Services para el Behavior Tree totalmente
desde C++.
Incluyendo el AIModule en nuestro proyecto.
Uno de los errores ms comunes cuando se est comenzando en el mundo de C++ en
UE4 y se crean clases que heredan de clases del framework que se encuentran en otros
mdulos, es que no se le dice a nuestro proyecto que vamos a usar clases de ese otro
mdulo. Cuando pasa esto e intentamos compilar el cdigo nos da muchsimos errores
de tipo Linker que bsicamente vienen dados porque estamos usando clases que el
compilador no encuentra.
Para nuestro caso, como vamos a hacer referencia a varias clases del mdulo de AI,
tenemos que incluir el mdulo AIModule. Cuando creamos un proyecto
automticamente se crea el archivo PROYECTO.Build.cs, es en este archivo donde
tenemos que indicar los mdulos que usamos en el cdigo.
Abre la clase UE4Demo.Build.cs y vers que tiene la siguiente lnea:
1PublicDependencyModuleNames.AddRange(new string[] { "Core",

"CoreUObject", "Engine", "InputCore"});

Como puedes notar, es un arreglo de strings con el nombre de los mdulos que usa
nuestro proyecto, por defecto ya vienen incluidos los mdulos bsicos. Como vamos a
usar clases del modulo AIModule, agrega al final del arreglo otro string con el nombre
del modulo. Te quedar de la siguiente forma:
PublicDependencyModuleNames.AddRange(new string[] { "Core",

1"CoreUObject", "Engine", "InputCore", "AIModule" });

Ahora si podemos incluir en nuestro proyecto cualquier clase del Mdulo AI y no nos
dar error. Si quieres, para probar exactamente lo que pasa, al final del tutorial prueba
eliminar este tem del arreglo y trata de compilar.
Recordando lo que hicimos en el tutorial pasado
En el tutorial pasado implementamos varios algoritmos mediante visualscripting y los
usamos en nodos del Behavior Tree del AIController para definir el comportamiento del
enemigo. Bsicamente implementamos tres algoritmos:
CheckNearbyEnemy que lo usamos en un Service del Behavior Tree y nos sirve para
determinar en cada update si el personaje principal est cerca del NPC haciendo uso del
MultiSphereTraceForObjects.
UpdateNextTargetPoint que lo usamos en un Task del Behavior Tree para determinar
el siguiente punto de la ruta que patrulla el enemigo
MoveToEnemy que lo usamos tambin en un Task y se llama cuando el algoritmo
CheckNearbyEnemy detecta que estamos cerca del enemigo y haciendo uso del mtodo
AI Move To hacemos que el enemigo nos persiga.
Para este acercamiento a C++ en Unreal Engine 4 vamos a re implementar estos tres
algoritmos pero totalmente desde C++.
Creando el AIController desde C++
Lo primero es crear nuestra clase C++ que heredar de AIController y que ser el
controlador del NPC. Crea una nueva clase desde el Editor File/Add Code To Project.
Selecciona como clase base AIController y de nombre dale AIEnemyCppController,
cuando el Editor te pregunte si quieres abrirla en el IDE le dices que s. Tendrs la
siguiente clase creada:
1
2
3
4
5
6
7
8
9

//AIEnemyCppController.h
#pragma once
#include "AIController.h"
#include "AIEnemyCppController.generated.h"
/** Clase Controladora del NPC del juego */
UCLASS()
class UE4DEMO_API AAIEnemyCppController : public AAIController

1
0
11
1
2
1
3
1
4 {
1 }; GENERATED_UCLASS_BODY()
5
1 //AIEnemyCppController.cpp
6
1 #include "UE4Demo.h"
7 #include "AIEnemyCppController.h"
1
8 AAIEnemyCppController::AAIEnemyCppController(const class
FPostConstructInitializeProperties& PCIP)
1
: Super(PCIP)
9 {
2
0 }
2
1
2
2
2
3
2
4
Compila el proyecto y ejectalo.
Creando el AIEnemyCppControllerBlueprint.
Aunque pudiramos hacer completamente el AIController desde C++. Vamos a crear un
Blueprint a partir de esta clase para poder extender el comportamiento del AIController
desde VisualScripting, en caso que queramos. Crea un Blueprint que herede de
AIEnemyCppController. Yo lo llam AIEnemyCppControllerBlueprint
Abre el AIEnemyCharacter que creamos en el tutorial pasado selecciona el modo
Defaults, seccin AI, y en el atributo AI Controller Class selecciona
AIEnemyCppControllerBlueprint. Guarda y Compila.
Ya cambiamos el controlador de nuestro enemigo, si corres el juego en este punto vers
que el NPC no har absolutamente nada, como es de esperar. Crea un nuevo Behavior
Tree para este estudio, podemos usar el anterior, pero vamos a crear uno nuevo para no
modificar el anterior y que te quede de referencia. Ya sabes como crear un Behavior
Tree (desde el Content Browser: New/Miscellaneous/Behavior Tree) y ponle de nombre
AIEnemyCppBehaviorTree simplemente para distinguirlo del otro.

Abre el AIEnemyCppControllerBlueprint y como mismo hicimos en el tutorial pasado,


agrega al Blueprint el nodo Event Begin Play conctalo al Run Behavior Tree y
selecciona en BTAsset este nuevo Behavior Tree que creamos.

Creando el AIEnemyTargetPoint mediante C++


En el tutorial pasado definimos el recorrido del enemigo con puntos clave en el nivel.
Estos puntos los creamos mediante un Blueprint que hereda de TargetPoint y le
agregamos un atributo Position que nos sirve para indicar el orden del recorrido. Vamos
a hacer esto mismo, pero totalmente desde C++, de esta forma tambin veremos algo
nuevo, veremos que podemos agregar al nivel directamente una clase creada en C++,
sin tener que crear un Blueprint que herede de ella como hemos hecho hasta ahora.
Agrega una nueva clase al cdigo de nombre AIEnemyTargetPointCpp que herede de
ATargetPoint. Modifica la declaracin de la clase para que te quede de la siguiente
forma:
1
2
3
4
5
6
7
8
9

//AIEnemyTargetPointCpp.h
#pragma once
#include "Engine/TargetPoint.h"
#include "AIEnemyTargetPointCpp.generated.h"
/** TargetPoint con el que definimos los puntos claves del recorrido
del AIEnemyCharacter */
UCLASS()
class UE4DEMO_API AAIEnemyTargetPointCpp : public ATargetPoint

1
0
11
1
2
1
3
1
4
1
5 {
GENERATED_UCLASS_BODY()
1
6
/** Representa el orden que tiene este TargetPoint en el
1 recorrido del personaje (siendo 0 el punto inicial) */
7
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Tutorial
Category")
1
int32 Position;
8
};
1
9
2 //AIEnemyTargetPointCpp.cpp
0
2 #include "UE4Demo.h"
1 #include "AIEnemyTargetPointCpp.h"
2
2
2 AAIEnemyTargetPointCpp::AAIEnemyTargetPointCpp(const class
PCIP)
3 FPostConstructInitializeProperties&
: Super(PCIP)
2 {
4 }
2
5
2
6
2
7
2
8
2
9
Simplemente agregamos a la clase el atributo Position de tipo entero. Gracias al macro
UPROPERTY con el atributo EditAnywhere podemos ver Position desde el Editor y
editar su valor. Con BlueprintReadWrite lo definimos para que tambin lo podamos
manipular desde el Blueprint y Category representa un nombre de seccin para
mostrarlo en el Editor. Vers que el atributo Position sale en el panel de detalles del
actor en una seccin de nombre Tutorial Category.
Cambiando los TargetPoint que tenemos en el nivel por los
AIEnemyTargetPointCpp.

Compila y ejecuta el cdigo. Actualmente en el nivel tenemos los cuatro puntos que
definen el recorrido del NPC, vamos a cambiar estos por los AIEnemyTargetPointCpp
que acabamos de crear desde C++. Selecciona cada uno y elimnalos del nivel. Ahora,
desde el panel Modes que tienes en la esquina superior izquierda tienes la seccin All
Classes, marca esa seccin y localiza la clase AIEnemyTargetPointCpp.
Desde aqu podemos agregar al nivel instancias de esta clase sin tener que crear un
blueprint como habamos hecho hasta el momento. Arrastra cuatro instancias de esta
clase al nivel, ve seleccionando cada una y modificando en el panel de Detalles dentro
de la seccin Tutorial Category el valor del atributo Position a 0,1,2,3 como mismo
hicimos en el tutorial pasado.

Implementando el algoritmo del UpdateNextTargetPoint desde C++


En el tutorial pasado lo primero que hicimos fue implementar el Task
UpdateNextTargetPoint que se encargaba de determinar cual era el siguiente TargetPoint
al que tena que moverse el NPC y setearlo en el Blackboard. Vamos a hacer esto mismo
pero totalmente desde programacin.
Abre la clase AAIEnemyCppController y en la .h agrega la siguiente declaracin
1/** Usado desde el Task UpdateNextTarhetPointBTTaskNode del Behavior
Tree para actualizar el siguiente punto en la ruta que patrulla */
2UFUNCTION(BlueprintCallable, Category="Tutorial Category")
3void UpdateNextTargetPoint();
Ahora pasa a la .cpp y agrega la implementacin del mtodo:
1
2
3
4

/** Usado desde el Task UpdateNextTarhetPointBTTaskNode del Behavior


Tree para actualizar el siguiente punto en la ruta que patrulla */
void AAIEnemyCppController::UpdateNextTargetPoint()
{

//Obtiene la referencia al BlackboardComponent del AIController


5
UBlackboardComponent* BlackboardComponent = BrainComponent6 >GetBlackboardComponent();
7
8
//Guarda en TargetPointNumber el valor que tiene el Blackboard
9 en el KEY TargetPointNumber
//Este numero representa el orden en el que se mueve el enemigo
1
por
los TargetPoint del nivel
0
int32 TargetPointNumber = BlackboardComponent11>GetValueAsInt("TargetPointNumber");
1
2
//Como solo tenemos 4 TargetPoint, cuando ya est en el ltimo,
1 que lo reinicie al primero.
if(TargetPointNumber >= 4)
3
{
1
//Pone en 0 el valor del KEY TargetPointNumber del
4 Blackboard
1
TargetPointNumber = 0;
5
BlackboardComponent->SetValueAsInt("TargetPointNumber",
1 TargetPointNumber);
}
6
1
//Iteramos por todos los AAIEnemyTargetPointCpp que hay en el
7 nivel
1
for (TActorIterator<AAIEnemyTargetPointCpp> It(GetWorld()); It; +
8 +It)
{
1
//Obtenemos el TargetPoint actualmente en el ciclo
9
AAIEnemyTargetPointCpp* TargetPoint = *It;
2
0
//Si el TargetPointNumber del BlackBoard es igual al valor
2 del atributo Position del AAIEnemyTargetPointCpp
//Este es el siguiente punto al que tiene que moverse el NPC
1
por
lo
que
setteamos el KEY TargetPointPosition con la posicion de
2
ese Actor
2
if(TargetPointNumber == TargetPoint->Position)
2
{
3
//Setteamos el KEY TargetPointPosition con la posicion
2 de ese TargetPoint en el nivel y detenemos el ciclo con el break;
BlackboardComponent4
>SetValueAsVector("TargetPointPosition", TargetPoint2 >GetActorLocation());
5
break;
}
2
}
6
2
//Por ltimo, incrementamos el valor de TargetPointNumber del
7
Blackboard
2
BlackboardComponent->SetValueAsInt("TargetPointNumber",
8 (TargetPointNumber + 1));
2
9 }
3
0
3
1
3
2

3
3
3
4
3
5
3
6
3
7
3
8
Ve con detenimiento por los comentarios de cada lnea para comprender en detalles lo
que se hace y como se usan las clases y mtodos que brinda el Framework.
En la declaracin del mtodo usamos el macro UFUNCTION con el atributo
BlueprintCallable. Esto es para poder llamar a este mtodo desde un Blueprint en caso
que nos haga falta. El mtodo tiene de tipo de dato void porque no retorna nada,
simplemente hace un procesamiento interno sin devolver ningn valor.
En la implementacin si tenemos algunos puntos importantes en los que detenernos.
Primero, fjate que para obtener la referencia al BlackBoard usamos el atributo
BrainComponent del AIController (la clase padre de nuestra clase). El BrainComponent
tiene un mtodo de nombre GetBlackboardComponent que nos permite obtener una
referencia al BlackBoard que est usando este AIController para su base de
conocimiento. Mediante este objeto de tipo UBlackboardComponent podemos usar el
mismo principio que usamos en el Blueprint para settear u obtener un valor del
BlackBoard.
Con SetValueAsTIPO_DE_DATO podemos settear el valor de un KEY determinado. El
primer parmetro es el KEY y el segundo es el valor. Con el mtodo
GetValueAsTIPO_DE_DATO podemos obtener el valor almacenado en un KEY del
blackboard, como parmetro espera el nombre del Key y retorna el valor almacenado en
ese KEY.
Lo primero que tenemos en cuenta es comparar si el TargetPointNumber es superior al
mximo que tenemos en el nivel, si es as, lo ponemos de nuevo en cero, para garantizar
que el recorrido del personaje sea indefinido y siguiendo siempre el mismo orden.
A continuacin usamos un Iterador muy til que nos brinda el Framework. Desde C++
podemos usar TActorIterator para iterar por todos los Actores del nivel de la clase que
indiquemos. En este caso nuestro objetivo es iterar por todos los
AAIEnemyTargetPointCpp
Dentro del loop lo que hacemos es obtener la referencia del objeto actual en el iterador ,
comparamos el valor del atributo Position con el valor que tenemos en la variable
TargetPointNumber que tiene el valor que tenemos en el KEY del BlackBoard, si son
iguales, seteamos el KEY TargetPointPosition del blackboard con la posicin de ese

TargetPoint en el nivel usando el mtodo GetActorLocation() que nos retorna el vector


con la posicin del actor.
Por ultimo, incrementamos el valor del KEY TargetPointNumber en 1 para que la
siguiente vez que se llame este mtodo se obtenga la posicin del siguiente punto en el
recorrido.
Fjate que en esta clase estamos haciendo referencia a AAIEnemyTargetPointCpp por lo
que tenemos que incluir al inicio, el fichero donde se define esta clase.
Creando el UpdateNextTargetPointTask del Behavior Tree desde C++
Ya tenemos listo el mtodo para determinar el siguiente punto del recorrido, pero como
sabes, este mtodo lo tenemos que usar en un Task para que forme parte de un nodo del
Behavior Tree. Vamos a crear este Task completamente desde C++
Compila y ejecuta el proyecto. Desde el editor agrega una nueva clase al proyecto que
herede de UBTTaskNode y ponle de nombre UpdateNextTargetPointBTTaskNode.
Abrela desde el IDE y modifica la .h para que te quede de la siguiente forma:
1
2
3 #pragma once
4
5 #include "BehaviorTree/BTTaskNode.h"
6 #include "UpdateNextTargetPointBTTaskNode.generated.h"
7
8 /** Task del Behavior Tree del AIEnemyCppController que ejecuta el
9 mtodo para seleccionar el siguiente punto del recorrido */
UCLASS()
1 class UE4DEMO_API UUpdateNextTargetPointBTTaskNode : public
0 UBTTaskNode
11{
GENERATED_UCLASS_BODY()
1
2
/* Se llama al iniciar este Task, tiene que retornar Succeeded,
1 Failed
o InProgress */
3
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent*
1 OwnerComp, uint8* NodeMemory) override;
4
/** Permite definir una descripcin para este Task. Este texto
1
se
ve
en el Nodo al agregarlo al Behavior Tree */
5
virtual FString GetStaticDescription() const override;
1 };
6
1
7
Ahora pasa a la .cpp y agrega la implementacin de estos mtodos:
1 #include "UE4Demo.h"
"AIEnemyCppController.h"
2 #include
#include "UpdateNextTargetPointBTTaskNode.h"
3

4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1

/** Constructor de la clase */


UUpdateNextTargetPointBTTaskNode::UUpdateNextTargetPointBTTaskNode(c
onst class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
//Definimos el nombre que tendr este Nodo en el Behavior Tree
NodeName = "UpdateNextTargetPoint";
}
/* Se llama al iniciar este Task, tiene que retornar Succeeded,
Failed o InProgress */
EBTNodeResult::Type
UUpdateNextTargetPointBTTaskNode::ExecuteTask(UBehaviorTreeComponent
* OwnerComp, uint8* NodeMemory)
{
//Obtenemos la referencia al AIEnemyController
AAIEnemyCppController* AIEnemyController =
Cast<AAIEnemyCppController>(OwnerComp->GetOwner());
//Llamamos al mtodo UpdateNextTargetPoint que tiene la lgica
para seleccionar el siguiente TargetPoint
AIEnemyController->UpdateNextTargetPoint();
//Finalmente retornamos Succeeded
return EBTNodeResult::Succeeded;
}
/** Permite definir una descripcin para este Task. Este texto se ve
en el Nodo al agregarlo al Behavior Tree */
FString UUpdateNextTargetPointBTTaskNode::GetStaticDescription()
const
{
return TEXT("Actualiza el siguiente punto en el recorrido");
}

Es muy fcil crear un Task desde C++. Basta con heredar de UBTTaskNode. Para este
caso solo necesitamos sobrescribir dos mtodos. El mtodo ExecuteTask que se llama
cuando el Behavior Tree ejecuta este nodo. Simplemente obtenemos la referencia al
AIEnemyController desde el parmetro OwnerComp con el mtodo GetOwner,
llamamos al mtodo del AIEnemyController UpdateNextTargetPoint que acabamos de
crear y que se encarga de toda la lgica necesaria para determinar y configurar el
siguiente punto del recorrido. Por ltimo retornamos Succeeded, como mismo hicimos
en el tutorial pasado, para que el nodo padre, el Sequence, contine con la ejecucin del
siguiente nodo.
El mtodo GetStaticDescription nos sirve para retornar un string con una descripcin
para este Task. Esta descripcin se ve en el Behavior Tree y resulta muy til para el caso
en el que sea otra persona la encargada de disear el Behavior Tree desde el Editor.
Compila y ejecuta el proyecto. Desde el Editor abre el Behavior Tree, vers que entre
los Tasks que puedes agregar tendrs este que acabamos de crear completamente desde
C++. Modifica el Behavior Tree para que te quede de la siguiente forma:

Compila, guarda y ejecuta el juego. Como vez, tenemos el personaje movindose por
los cuatro puntos exactamente a como lo logramos anteriormente, la diferencia es que
ahora todo lo hemos hecho desde C++.
Implementado el mtodo CheckNearbyEnemy
Vamos ahora a implementar el mtodo CheckNearbyEnemy en el AIController, que es
el mtodo que hace uso del MultiSphereTraceForObjects para detectar si nos hemos

acercado al enemigo. Agrega la declaracin del mtodo en la .h del


AAIEnemyCppController
/**

1 * Chequea si el personaje est cerca y setea una referencia a l en


2el BlackBoard
* Es usado en Service CheckNearbyEnemyBTService del Behavior Tree
3para
estar constantemente vigilando si se acerca alguien a la zona de
4patrulla.
5 */
6UFUNCTION(BlueprintCallable, Category="Tutorial Category")
void CheckNearbyEnemy();

Ahora pasa al .cpp y agrega la siguiente implementacin:


1 /**
2 * Chequea si el personaje est cerca y setea una referencia a l en
el BlackBoard
3 * Es usado en Service CheckNearbyEnemyBTService del Behavior Tree
4 para estar constantemente vigilando si se acerca alguien a la zona de
5 patrulla.
6 */
void AAIEnemyCppController::CheckNearbyEnemy()
7{
8
//Obtenemos la referecia al Pawn del NPC
9
APawn *Pawn = GetPawn();
1
//Guardamos en MultiSphereStart la posicin del NPC
0
FVector MultiSphereStart = Pawn->GetActorLocation();
1
1
//Creamos un nuevo vector a partir de la posicin del NPC pero
1 con un incremente en la Z de 15 unidades.
2
//Estos dos valores sern los puntos de inicio y fin del
1 MultiSphereTraceForObjects
FVector MultiSphereEnd = MultiSphereStart + FVector(0, 0, 15.0f);
3
1
//Creamos el arreglo que pasaremos como el parmetro ObjectTypes
4
del MultiSphereTraceForObjects y define los tipos de objetos a tener
1 en cuenta
5
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_Pawn));
1
6
//Creamos el arreglo de los actores a ignorar por el mtodo,
1
solamente con el Pawn del NPC que es el nico que no puede estar en
7 el resultado
1
TArray<AActor*> ActorsToIgnore;
8
ActorsToIgnore.Add(Pawn);
1
//OutHits la usaremos como parmetro de salida. Como el mtodo
9
2 SphereTraceMultiForObjects recibe la referencia de este parmetro
//al terminar la ejecucin del mtodo en este arreglo se
0 encuentran el arreglo de FHitResult lleno con los Hits que detecte el
2 mtodo.
1
TArray<FHitResult> OutHits;
2
bool Result =
2
UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(),
2
//Referencia del Mundo
3

Mu
2
ltiSphereStart,
//Punto de Inicio de la recta que
4 define la esfera
2
Mu
5 ltiSphereEnd,
//Punto de fin de la recta que define
2 la esfera
70
6
0,
//Radio de la esfera
2
Ob
7 jectTypes,
//Tipos de objetos a tener en cuenta
2 en el proceso
fa
8
lse,
//No
queremos
que
se
use
el
modo
2
complejo
9
Ac
3 torsToIgnore,
//Los actores que se van a ignorar
0 aunque esten dentro de la esfera
ED
3
rawDebugTrace::ForDuration,
//El tipo de Debug
1
Ou
3 tHits,
//Parmetro por referencia donde se
2 guardarn los resultados
tr
3
ue);
//si
se
ignora
el
propio
objeto
3
3
//Inicialmente seteamos en NULL el KEY del BlackBoard
4 TargetActorToFollow para en caso de que en el Trace no se tenga
3 resultados, se quede en NULL
5
UBlackboardComponent* BlackboardComponent = BrainComponent>GetBlackboardComponent();
3
BlackboardComponent->SetValueAsObject("TargetActorToFollow",
6
NULL);
3
7
//Si hay resultados en el Trace
3
if(Result == true)
{
8
//Recorremos todos los objetos dentro del OutHits
3
for(int32 i = 0; i < OutHits.Num(); i++)
9
{
4
//Obtenemos el FHitResult actualmente en el ciclo
0
FHitResult Hit = OutHits[i];
4
//Obtenemos la referencia el Character
1
ACharacter* Character =
4
UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
2
4
//Si el Actor detectado en el Trace es igual al Character
3
//setamos el KEY TargetActorToFollow del Blackboard con
4 la referencia al Character
if(Hit.GetActor() == Character)
4
{
4
BlackboardComponent5 >SetValueAsObject("TargetActorToFollow", Character);
4
}
}
6
}
4
}
7
4
8

4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
La lgica que sigue est mtodo tampoco es necesaria explicarla porque ya lo hicimos
en el tutorial pasado cuando lo implementamos mediante VisualScripting, pero si vamos
a pasar por el cdigo para ver los detalles del Framework y las clases y mtodo que nos
permiten hacer esto mismo desde C++.
Primero preparamos las variables que vamos a pasar como parmetro al mtodo del
Trace. El nico que creo que vale la pena comentar es la variable ObjectTypes que es un
arreglo de TEnumAsByte Este es el tipo de dato del parmetro ObjectTypes que recibe
el mtodo del Trace. Fjate que solamente le agregamos un elemento, el indicador de
Pawn. UEngineTypes::ConvertToObjectType nos permite convertir el ECC_Pawn
(valor de enum correspondiente al Pawn) a un EObjectTypeQuery. La siguiente variable
que declaramos es el arreglo de Actors que va a ignorar el Trace, recuerda que aqu
solamente incluimos al Pawn del enemigo, que lo tenemos en la variable Pawn y
obtenemos la referencia a este mediante el mtodo GetPawn.
Por ltimo declaramos el arreglo OutHits que lo usaremos como parmetro de salida. El
mtodo SphereTraceMultiForObjects recibe este parmetro por referencia y al terminar

la ejecucin, el arreglo de FHitResults queda poblado con los Hits que detecte el
mtodo. Los parmetros por referencia son la variante que tenemos en C++ para tener
ms de un valor de retorno en una funcin.
Y ahora el punto clave de este mtodo, la llamada al
UKismetSystemLibrary::SphereTraceMultiForObjects. SphereTraceMultiForObjects es
un mtodo esttico dentro de la clase UKismetSystemLibrary y ya sabemos lo que
hace :)
Despus de su ejecucin seteamos en NULL el KEY TargetActorToFollow del
Blackboard para que en caso de que no se encuentre el Pawn del personaje dentro del
Trace, que se quede este KEY en NULL. Recuerda que el Decorator que tenemos en el
Behavior Tree para determinar si se ejecuta o no el siguiente Task se basa en comprobar
si el KEY TargetActorToFollow tiene valor.
Creando el CheckNearbyEnemyService desde C++
Como mismo hicimos para el Task anterior, tenemos que crear el Service del Behavior
Tree donde se va a usar este mtodo que acabamos de crear. Compila y ejecuta el
proyecto, desde el editor crea una nueva clase que herede de UBTService y ponle de
nombre UCheckNearbyEnemyBTService. Abrela en el IDE y modifica el .h para que te
quede de la siguiente forma:
1
2
3 #pragma once
4
5 #include "BehaviorTree/BTService.h"
6 #include "CheckNearbyEnemyBTService.generated.h"
7 /** Service del Behavior Tree del AIEnemyCppController que chequea
8 constantemente si el personaje est cerca de nosotros */
9 UCLASS()
1 class UE4DEMO_API UCheckNearbyEnemyBTService : public UBTService
0 {
GENERATED_UCLASS_BODY()
11
1
/** Se llama en cada update del Service */
2
virtual void TickNode(UBehaviorTreeComponent* OwnerComp, uint8*
1 NodeMemory, float DeltaSeconds) override;
3 };
1
4
Ahora pasa al .cpp y modifcalo para que te quede de la siguiente forma:
1
2
3
4
5
6

#include "UE4Demo.h"
#include "AIEnemyCppController.h"
#include "CheckNearbyEnemyBTService.h"
/** Constructor de la clase */
UCheckNearbyEnemyBTService::UCheckNearbyEnemyBTService(const class
FPostConstructInitializeProperties& PCIP)

7
8
9
1
0
11
1
2
1
3
1
: Super(PCIP)
4
{
1
//Nombre del nodo en el Behavior Tree
5
NodeName = "CheckNearbyEnemy";
1
6
//Intervalo de Update
Interval = 0.5f;
1
7
//Aleatorio de desviacin para el update
1
RandomDeviation = 0.1f;
8 }
1
9 /** Se llama en cada update del Service */
2 void UCheckNearbyEnemyBTService::TickNode(UBehaviorTreeComponent*
0 OwnerComp, uint8* NodeMemory, float DeltaSeconds)
2 {
//Llamamos a la implementacin de la clase base primero
1
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
2
2
//Obtenemos la referencia del AIEnemyController
2
AAIEnemyCppController* AIEnemyController =
3 Cast<AAIEnemyCppController>(OwnerComp->GetOwner());
2
//Llamamos al mtodo CheckNearbyEnemy del AIEnemyController que
4
tiene toda la lgica para determinar si el enemigo est cerca o no
2
//y configurar el KEY correspondiente del Blackboard
5
AIEnemyController->CheckNearbyEnemy();
2 }
6
2
7
2
8
2
9
3
0
3
1
No hay mucho que explicar aqu verdad ? En el constructor inicializamos los valores del
Services que ya conoces del tutorial anterior, y en el mtodo TickNode obtenemos la

referencia del AIEnemyController y llamamos al mtodo CheckNearbyEnemy que se


encarga de todo :)
Compila y ejecuta el proyecto. Abre el Behavior Tree y modifcalo para que te quede de
la siguiente forma:

Guarda, Compila y ejecuta el juego.

Muy bien, ya solo nos queda el ltimo paso para terminar el Behavior Tree que
implementamos en el tutorial pasado pero en esta ocasin completamente desde C++.
Implementado el mtodo MoveToEnemy
Vamos a implementar el ltimo mtodo del AIEnemyController, el encargado de llamar
al MoveToActor para comenzar la persecucin :). Abre AIEnemyCppController.h y
agrega la siguiente declaracin
/**

1 * Hace que el AIEnemyCharacter persiga al actor setteado en el KEY


2TargetActorToFollow del Blackboard
3 * Es usado en un Task del Behavior Tree para perseguir al personaje
principal
4 * @return El resultado del mtodo MoveToActor (Failed,
5AlreadyAtGoal o RequestSuccessful)
6 */
7UFUNCTION(BlueprintCallable, Category="Tutorial Category")
EPathFollowingRequestResult::Type MoveToEnemy();

Ahora pasa a la .cpp y agrega la siguiente implementacin:


1
2
3
4
5
6
7
8
9
1
0

/**
* Hace que el AIEnemyCharacter persiga al actor setteado en el KEY
TargetActorToFollow del Blackboard
* Es usado en un Task del Behavior Tree para perseguir al
personaje principal
* @return El resultado del mtodo MoveToActor (Failed,
AlreadyAtGoal o RequestSuccessful)
*/
EPathFollowingRequestResult::Type
AAIEnemyCppController::MoveToEnemy()
{
//Obtenemos la referencia al BlackBoard
UBlackboardComponent* BlackboardComponent = BrainComponent-

11
1
2 >GetBlackboardComponent();
1
//Obtenemos la referencia al Actor guardado en el KEY
3 TargetActorToFollow del BlackBoard
1
AActor* HeroCharacterActor = Cast<AActor>(BlackboardComponent4 >GetValueAsObject("TargetActorToFollow"));
1
//Iniciamos el proceso de perseguir al personaje
5
EPathFollowingRequestResult::Type MoveToActorResult =
1
MoveToActor(HeroCharacterActor);
6
1
return MoveToActorResult;
7 }
1
8
Fjate que usamos el mtodo MoveToActor de AIController para comenzar la
persecucin, lo dems no creo que necesite explicacin. Aqu usamos el mtodo
MoveToActor pasndole solo el parmetro del Actor que tiene que seguir, pero date una
vuelta por la declaracin del mtodo para que veas los otros parmetros que se le puede
pasar.
Creando el MoveToEnemyBTTaskNode desde C++
Por ltimo nos queda crear el Task que usar este mtodo. Pero, vamos a detenernos
aqu para comentar un poco de teora que se me pas en el tutorial pasado.
En Unreal Engine 4 los Tasks pueden ser de dos tipos. Los que se ejecutan y tienen un
resultado al instante, como el UpdateNextTargetPoint, y los que demoran un tiempo en
terminar su ejecucin. En este caso se encuentra este Task que vamos a crear, ya que la
accin de este Task va a terminar cuando el enemigo llegue al personaje principal, y
esto puede demorar un tiempo.
Este tipo de Task generalmente en su ejecucin retornan InProgress para que el
Behavior Tree sepa que demorar un poco en terminar, y se usa el mtodo TickTask para
estar comprobando la condicin que se tiene que cumplir para que termine la ejecucin
del Task y en ese momento se termina la ejecucin con una llama al mtodo
FinishLatentTask.
Vamos a verlo en la practica con la creacin de este Task. Agrega una clase de nombre
MoveToEnemyBTTaskNode que herede de UBTTaskNode modifica su .h para que te
quede de la siguiente forma:
1
2
3
4
5
6
7

#pragma once
#include "BehaviorTree/BTTaskNode.h"
#include "MoveToEnemyBTTaskNode.generated.h"
/**
*
*/

8
9
1
0
11
1
2 UCLASS()
class UE4DEMO_API UMoveToEnemyBTTaskNode : public UBTTaskNode
1 {
3
GENERATED_UCLASS_BODY()
1
/* Se llama al iniciar este Task, tiene que retornar Succeeded,
4
Failed
o InProgress */
1
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent*
5 OwnerComp, uint8* NodeMemory) override;
1
6
/* Se llama constantemente. Es usado generalmente en Tasks que
1 en el ExecuteTask retornan InProgress */
virtual void TickTask(class UBehaviorTreeComponent* OwnerComp,
7
uint8*
NodeMemory, float DeltaSeconds) override;
1
8
/** @return Una descripcin para este Task. Este texto se ve en
1 el Nodo
al agregarlo al Behavior Tree */
9
virtual FString GetStaticDescription() const override;
2
0 };
2
1
2
2
2
3
Ahora pasa a la .cpp y modifcala para que te quede de la siguiente forma:
1 #include "UE4Demo.h"
"AIEnemyCppController.h"
2 #include
#include "MoveToEnemyBTTaskNode.h"
3
4 /** Constructor de la clase */
5 UMoveToEnemyBTTaskNode::UMoveToEnemyBTTaskNode(const class
6 FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
7
{
8
//Definimos el nombre que tendr este Nodo en el Behavior Tree
9
NodeName = "MoveToEnemy";
1
0
//Activamos para que se llame el TickTask de este task
bNotifyTick = true;
11
}
1
2
/* Se llama al iniciar este Task, tiene que retornar Succeeded,
1 Failed o InProgress */
3 EBTNodeResult::Type
1 UMoveToEnemyBTTaskNode::ExecuteTask(UBehaviorTreeComponent*
4 OwnerComp, uint8* NodeMemory)
{

1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9

//Obtenemos la referencia al AIEnemyController


AAIEnemyCppController* AIEnemyController =
Cast<AAIEnemyCppController>(OwnerComp->GetOwner());
//Preparamos el resultado del Task. En este caso como es un Task
que su ejecucin no terminar al instante, tiene que retornar
InProgress
EBTNodeResult::Type NodeResult = EBTNodeResult::InProgress;
//Llamamos al mtodo MoveToEnemy del Controller y guardamos en
MoveToActorResult el resultado
EPathFollowingRequestResult::Type MoveToActorResult =
AIEnemyController->MoveToEnemy();
//Este caso sera si se ejecuta este Task estando delante del
personaje. En este caso si retorna Succeeded
if (MoveToActorResult ==
EPathFollowingRequestResult::AlreadyAtGoal)
{
NodeResult = EBTNodeResult::Succeeded;
}
return NodeResult;
}
/* Se llama constantemente. Es usado generalmente en Tasks que en el
ExecuteTask retornan InProgress */
void UMoveToEnemyBTTaskNode::TickTask(class UBehaviorTreeComponent*
OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
//Obtenemos la referencia al AIEnemyController
AAIEnemyCppController* AIEnemyController =
Cast<AAIEnemyCppController>(OwnerComp->GetOwner());
//Llamamos al mtodo MoveToEnemy del Controller y guardamos en
MoveToActorResult el resultado
EPathFollowingRequestResult::Type MoveToActorResult =
AIEnemyController->MoveToEnemy();
//Si ya se llega al objetivo se termina la ejecucin el Task con
FinishLatentTask y un resultado
if (MoveToActorResult ==
EPathFollowingRequestResult::AlreadyAtGoal)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
}
}
/** @return Una descripcin para este Task. Este texto se ve en el
Nodo al agregarlo al Behavior Tree */
FString UMoveToEnemyBTTaskNode::GetStaticDescription() const
{
return TEXT("Persigue al personaje principal");
}

4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
Muy bien, la .h a estas alturas no creo que tenga nada que explicar. Ahora, en la cpp,
primero en el constructor tenemos que poner en true el atributo bNotifyTick para que el
Engine sepa que tiene que ejecutar el mtodo Tick de esta clase.
En el ExecuteTask simplemente llamamos al mtodo MoveToEnemy, este mtodo nos
retorna tres posibles valores Failed, AlreadyAtGoal o RequestSuccessful. Normalmente
el ExecuteTask tendr que terminar en InProgress a menos que el MoveToActor retorne
AlreadyAtGoal que sera dado si se llama el mtodo estando ya pegados al personaje.
De lo contrario retornamos InProgress para dejarle saber el BT que este Task tomar un
tiempo.
Entonces, en el TickTask es donde tenemos que estar comprobando si llega al objetivo,
si esto pasa se fuerza a terminar el Task con el mtodo FinishLatentTask.

Compila y ejecuta el proyecto. Modifica el Behavior Tree para agregar este ltimo Task
y el Decorator correspondiente como mismo lo hicimos en el tutorial pasado. Te
quedar de la siguiente forma:

Guarda, compila y ejecuta el juego ;)

Conclusin
A pesar de no implementar ninguna funcionalidad nueva en este tutorial, creo que sirvi
para acercarnos un poco ms al mundo de C++ en el Unreal Engine 4. Puedes bajarte de
aqu las clases que hemos creado en este tutorial para una referencia directa.
Con esto terminamos por hoy, en el prximo tutorial le ensearemos a nuestro
personaje a dar puetazos para que se pueda defender cuando el enemigo lo atrape :)
mientras, me encantara escuchar tus comentarios.

Cmo causar dao a un personaje con


puetazos en UE4 Parte 1
2014/11/08 por nan2cc 5 comentarios
Hola, seguimos con esta serie de tutoriales sobre el desarrollo de juegos con Unreal
Engine 4. En este tutorial vamos a ensearle a nuestro personaje sus primeras
habilidades para defenderse. Vamos a ensearle a dar puetazos. Esto nos servir para
hacer una introduccin al Animation Montage, al Animation Composite, a los
mecanismo de colisin que nos brinda UE4, a los mtodos para causar dao a los Pawn,
a reproducir efectos de sonido y muchas cosas ms. Lo dividiremos en dos partes por su
extensin, aqu vamos con la primera.
Como siempre, vamos a partir del mismo proyecto con el que hemos estado trabajando
desde el inicio, pero antes de comenzar con el plato fuerte vamos a hacer una pequea

modificacin en la clase del HeroCharacter para facilitar el proceso de cambiar entre un


estilo de cmara y otro. Abre el cdigo fuente del proyecto y modifica la clase
HeroCharacter para que te quede de la siguiente forma:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

//------------------------------------------------------------------// File: HeroCharacter.h


//------------------------------------------------------------------#pragma once
#include "GameFramework/Character.h"
#include "HeroCharacter.generated.h"
/** Enum ayudante con los estilos de camara del juego */
typedef enum
{
CameraGameStyleSideScroller, //Estilo Side Scroller
CameraGameStyleTopDown
//Estilo Top Down
}
CameraGameStyle;
/** Constante para definir el estilo de juego */
#define GAME_STYLE CameraGameStyleSideScroller
/** Clase base del personaje principal */
UCLASS()
class UE4DEMO_API AHeroCharacter : public ACharacter
{
GENERATED_UCLASS_BODY()
/** Brazo para apoyar fijar la cmara al Character al estilo
side-scroller */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<USpringArmComponent> SpringArm;
/** Cmara del juego, es adjuntada al socket del brazo para
lograr el estilo de cmara de un side-scroller */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<UCameraComponent> SideViewCamera;
/** Cantidad de monedas recolectadas por el personaje */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Coins)
int32 CoinsCollected;
/**
* Se llama cuando el motor detecta la entrada Run
* Intercambia el estado de correr del personaje
*/
void ToggleRunState();
/**
* Inicializa las variables SpringArm y SideViewCamera con la
configuracion necesaria
* para una vista side-scroller
*/
void InitSideScrollerCamera(const class

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

FPostConstructInitializeProperties& PCIP);
/**
* Inicializa las variables SpringArm y SideViewCamera con la
configuracion necesaria
* para una vista topdown
*/
void InitTopDownCamera(const class
FPostConstructInitializeProperties& PCIP);
/**
* Se llama cuando el motor detecta la entrada configurada para
'MoveRight'.
* En este caso cuando el usuario toca la tecla A o D del
teclado
*/
void MoveRight(float Value);
/**
* Se llama cuando se detecta la entrada de tipo MoveForward
(W o S).
* Determina la direccin en la que est el personaje y le
aplica un movimiento (positivo o negativo) en esa direccin
*
* @param Value es igual a 1 cuando se detecta W y -1 cuando
se detecta S
*/
void MoveForward(float Value);
/** Se llama constantemente en el Tick del personaje para
determinar si se est colisionando con una moneda */
void CollectCoins();
/**
* Se ejecuta automticamente por el Engine en cada frame del
juego
* @param DeltaSeconds la diferencia en segundos entre el frame
pasado y el actual
*/
virtual void Tick(float DeltaSeconds) OVERRIDE;
/**
* Metodo de la clase APawn que permite configurar los
'binding' de los controles
* Es llamado automaticamente por el Engine
*/
virtual void SetupPlayerInputComponent(class UInputComponent*
InputComponent) OVERRIDE;
};

//------------------------------------------------------------------// File: HeroCharacter.cpp


//-------------------------------------------------------------------

97 #include "UE4Demo.h"
"Coin.h"
98 #include
#include "HeroCharacter.h"
99
10
0 AHeroCharacter::AHeroCharacter(const class
10 FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
1
{
10
//Por defecto esta propiedad viene en true para el Character.
2
//Pero en nuestro modelo de desplazamiento, no queremos que el
10 personaje rote en base a la rotacin del Controller.
3
bUseControllerRotationYaw = false;
10
//Configuracin del componente CharacterMovement
4
10
//Al estar en true habilita para que el character se rote en la
5
direccin del movimiento al comenzar el movimiento.
10
CharacterMovement->bOrientRotationToMovement = true;
6
10
//Factor de rotacin para la propiedad anterior.
7
CharacterMovement->RotationRate = FRotator(0.0f, 540.0f, 0.0f);
10
//Bajamos un poco el valor por defecto de MaxWalkSpeed para que
8
10 el personaje camine un poco ms lento.
CharacterMovement->MaxWalkSpeed = 400.0f;
9
11
//Segun el valor de la constante GAME_STYLE llamamos al metodo
0 correspondiente para configurar los componentes SpringArm y camera
111
switch (GAME_STYLE)
{
11
case CameraGameStyleTopDown:
2
InitSideScrollerCamera(PCIP); //Inicializa SpringArm y
11 SideViewCamera para una vista de juego estilo side-scroller
3
break;
11
case CameraGameStyleSideScroller:
4
InitTopDownCamera(PCIP);//Inicializa SpringArm y
11
SideViewCamera
para una vista de juego estilo top-down
5
break;
11
6
default: break;
11
}
7
CoinsCollected = 0;
11
}
8
11
Inicializa SpringArm y SideViewCamera para una vista de juego
9 /**
estilo side-scroller */
12 void AHeroCharacter::InitSideScrollerCamera(const class
0 FPostConstructInitializeProperties& PCIP)
12 {
//Inicializando la instancia del USpringArmComponent
1
SpringArm =
12 PCIP.CreateDefaultSubobject<USpringArmComponent>(this,
2 TEXT("CameraBoom"));\
12
3
//Agregando el springArm al RootComponent del Character (la

12
4
12
5
12
6
12
7
12
8
12
9
13
0
13
1
13
2
13
3
13
4
13
5
13
6
13
7
13
8
13
9
14
0
14
1
14
2
14
3
14
4
14
5
14
6
14
7
14
8

capsula de colisin)
SpringArm->AttachTo(RootComponent);
//bAbsoluteRotation nos permite definir si este apoyo para la
cmara rotar junto con el player.
//En este caso no queremos que rote junto al character
SpringArm->bAbsoluteRotation = true;
//La distancia entre el brazo y su objetivo. Este valor es el
que define la distancia de la cmara.
//Prueba con distintos valores para que veas el resultado.
SpringArm->TargetArmLength = 500.f;
//Offset que tendr el Socket.
//Un Socket es un punto de anclaje para otros componentes.
//Por ejemplo, para el caso de un personaje podemos definir que
tenga un socket en la zona de la mano
//de esta forma le podemos agregar otro componente (como un
arma, por ejemplo) en la mano
//En nuestro SpringArm, en este socket es donde se agregar la
cmara
SpringArm->SocketOffset = FVector(0.f,0.f,75.f);
//La rotacin relativa que tendr este brazo con respecto al
padre.
//En este caso queremos que este rotada en el eje Y 180 grados
para que quede paralela al character a su mismo nivel.
//De esta forma logramos el clsico estilo de cmara en los
side-scrollers
SpringArm->RelativeRotation = FRotator(0.f,180.f,0.f);
// Creando la intancia del tipo UCameraComponent
SideViewCamera =
PCIP.CreateDefaultSubobject<UCameraComponent>(this,
TEXT("SideViewCamera"));
//El mtodo AttachTo nos permite agregar un objeto a otro
objeto en un socket determinado. Recibe dos parmetros.
//el primero, el objeto al que vamos a anclarnos, en este
el springArm y el nombre del socket donde lo vamos a anclar
//SocketName de USpringArmComponent retorna el nombre del
Socket de este componente.
SideViewCamera->AttachTo(SpringArm,
USpringArmComponent::SocketName);

caso

}
/** Inicializa SpringArm y SideViewCamera para una vista de juego
estilo top-down */
void AHeroCharacter::InitTopDownCamera(const class
FPostConstructInitializeProperties& PCIP)
{
CharacterMovement->bConstrainToPlane = true;
CharacterMovement->bSnapToPlaneAtStart = true;
SpringArm =
PCIP.CreateDefaultSubobject<USpringArmComponent>(this,
TEXT("CameraBoom"));
SpringArm->AttachTo(RootComponent);

14
9
15
0
15
1
15
2
15
3
15
4
15
5
15
6
15
7
15
8
15
9
16
0
16
1
16
2
16
3
16
4
16
5
16
6
16
7
16
8
16
9
17
0
17
1
17
2
17
3

SpringArm->bAbsoluteRotation = true;
SpringArm->TargetArmLength = 800.f;
SpringArm->RelativeRotation = FRotator(-60.f, 0.f, 0.f);
SpringArm->bDoCollisionTest = false;
SideViewCamera =
PCIP.CreateDefaultSubobject<UCameraComponent>(this,
TEXT("TopDownCamera"));
SideViewCamera->AttachTo(SpringArm,
USpringArmComponent::SocketName);
SideViewCamera->bUseControllerViewRotation = false;
}
void AHeroCharacter::SetupPlayerInputComponent(class
UInputComponent* InputComponent)
{
//Le dice al motor que cuando detecte las entrada de tipo
MoveRight que llame al metodo AHeroCharacter::MoveRight
InputComponent->BindAxis("MoveRight", this,
&AHeroCharacter::MoveRight);
//Solo este input se usa en el estilo TopDown
if(GAME_STYLE == CameraGameStyleTopDown)
InputComponent->BindAxis("MoveForward", this,
&AHeroCharacter::MoveForward);
//Le dice al motor que cuando detecte la entrada de tipo Jump
(barra espaciadora) llame al metodo Jump de la clase ACharacter (la
clase padre de esta)
InputComponent->BindAction("Jump", IE_Pressed, this,
&ACharacter::Jump);
//Le dice al motor que cuando detecte la entrada de tipo Run
(Shift) estando presionada la tecla, llame al metodo
ToggleRunState.
InputComponent->BindAction("Run", IE_Pressed, this,
&AHeroCharacter::ToggleRunState);
//Le dice al motor que cuando detecte la entrada de tipo Run
(Shift) al soltar la tecla, llame al metodo ToggleRunState.
InputComponent->BindAction("Run", IE_Released, this,
&AHeroCharacter::ToggleRunState);
}
/**
* Se llama cuando se detecta la entrada de tipo MoveForward (W o
S).
* Determina la direccin en la que est el personaje y le aplica
un movimiento (positivo o negativo) en esa direccin
*
* @param Value es igual a 1 cuando se detecta W y -1 cuando se
detecta S
*/
void AHeroCharacter::MoveForward(float Value)
{
if ((Controller != NULL) && (Value != 0.0f))
{
//Determina la direccin del movimiento hacia delante
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);

17
4
17
5
17
6
17
7
17
8
17
9
18
0
18
1
18
2
18
3
18
4
18
5
18
6
18
7
18
8
18
9
19
0
19
1
19
2
19
3
19
4
19
5
19
6
19
7
19
8

// Crea el vector de la direccin y aplica el movimiento


const FVector Direction =
FRotationMatrix(Rotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, -Value);
}
}
/**
* Se llama cuando se detecta la entrada de tipo MoveForward (A o
D).
* @param Value Value es igual a 1 cuando se detecta D y -1 cuando
se detecta A
*/
void AHeroCharacter::MoveRight(float Value)
{
//Si el estilo de juego es CameraGameStyleTopDown procesamos la
entrada MoveRight para lograr el movimiento que se aplique a este
estilo
if(GAME_STYLE == CameraGameStyleTopDown)
{
if ( (Controller != NULL) && (Value != 0.0f) )
{
//Determina la direccin del movimiento hacia los lados
const FRotator Rotation = Controller>GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);

movimiento

// Crea el vector de la direccin y aplica el

const FVector Direction =


FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(Direction, -Value);
}
return;
}
//Si el estilo de juego es CameraGameStyleSideScroller
procesamos la entrada MoveRight para lograr el movimiento que se
aplique a este estilo
if(GAME_STYLE == CameraGameStyleSideScroller)
{
if ( (Controller != NULL) && (Value != 0.0f) )
{
// Agrega un vector de movimiento hacia la derecha o la
izquierda segun el valor de Value
AddMovementInput(FVector(0.f,-1.f,0.f), Value);
}
return;
}
}

/**
* Se llama cuando el motor detecta la entrada Run
* Intercambia el estado de correr del personaje
*/
void AHeroCharacter::ToggleRunState()
{
//Si el atributo MaxWalkSpeed del CharacterMovement est en

19
9
20
0
20
1
20
2
20
3
20
4
20
5
20
6
20
7
20
8
20
9
21
0
21
1
21
2
21
3
21
4
21
5
21
6
21
7
21
8
21
9
22
0
22
1
22
2
22
3

400.f lo aumentamos a 900.f para que el personaje se mueva mas


rpido
//De lo contrario lo volvemos a poner en 400.f para que regrese
a su velocidad de caminar.
if(CharacterMovement->MaxWalkSpeed == 400.0f)
CharacterMovement->MaxWalkSpeed = 900.0f;
else
CharacterMovement->MaxWalkSpeed = 400.0f;
}
/** Se llama constantemente en el Tick del personaje para
determinar si se est colisionando con una moneda */
void AHeroCharacter::CollectCoins()
{
//Arreglo de AActors para guardar temporalmente todos los
Actors que se detecten que estn colisionando con el personaje
TArray<AActor*> CollectedActors;
//CapsuleComponent cuenta con el mtodo GetOverlappingActors.
Este metodo nos retorna en la llamada dentro del arreglo que le
pasamos por parmetro
//todos los objetos que estan dentro de la capsula en ese
momento.
CapsuleComponent->GetOverlappingActors(CollectedActors);
//Recorremos todos los objetos dentro del CapsuleComponent
for(int32 i = 0; i < CollectedActors.Num(); i++)
{
//Como el arreglo es de AActors tenemos que catear cada
elemento a ACoin antes de usarlo
ACoin *Coin = Cast<ACoin>(CollectedActors[i]);
//Nos aseguramos que la moneda est activa y que no ha sido
llamado an el mtodo Destroy
if(Coin != NULL && !Coin->IsPendingKill() && Coin>bIsActive)
{
//Incrementamos la cantidad de momendas recolectadas
CoinsCollected++;
//Por ltimo llamamos al OnCollected de la moneda para
ejecutar toda la lgica de la moneda cuando esta es tomada por el
personaje
Coin->OnCollected();
}
}
}
/**
* Se ejecuta automticamente por el Engine en cada frame del juego
* @param DeltaSeconds la diferencia en segundos entre el frame
pasado y el actual
*/
void AHeroCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
//En cada update del juego llamamos al CollectCoins para estar

22 constantemente determinando si se est colisionando con alguna


4 moneda
CollectCoins();
22 }
5
22
6
22
7
22
8
22
9
23
0
23
1
23
2
23
3
23
4
23
5
23
6
23
7
23
8
23
9
24
0
24
1
24
2
24
3
24
4
24
5
24
6
24
7
24
8

24
9
25
0
25
1
25
2
25
3
25
4
25
5
25
6
25
7
25
8
25
9
26
0
26
1
26
2
26
3
26
4
26
5
26
6
26
7
26
8
26
9
27
0
27
1
27
2
27
3

27
4
27
5
27
6
27
7
27
8
27
9
28
0
28
1
28
2
28
3
28
4
28
5
28
6
28
7
28
8
28
9
29
0
29
1
29
2
29
3
29
4
29
5
29
6
29
7
29
8

29
9
30
0
30
1
30
2
30
3
30
4
30
5
30
6
30
7
30
8
30
9
31
0
31
1
31
2
31
3
31
4
31
5
31
6
31
7
31
8
Aqu no hemos hecho nada especial. Recuerdas que ya tenamos un mtodo para adaptar
el juego para el estilo side-scroller y otro para el top-down? Pues lo que agregamos fue
la constante GAME_STYLE y una enum con las dos variantes de estilo que tenemos.
Para alternar entre un estilo de cmara y otro basta con modificar el valor de esta
constante.
Guarda, compila y ejecuta. Yo adems modifiqu el SpringArm del personaje desde el
editor en la seccin Transform, la propiedad Rotation la tengo en Absolute y con los
valores X = 0, Y = 10 y Z = 200. Esto para darle un poco de inclinacin a la cmara,

pero es cuestin de gusto, djala como la tenamos hasta ahora o ponla a tu gusto, como
prefieras.

Captura de la vista de nuestro juego


En estos momentos nuestro hroe camina, corre y salta, pero no tiene forma de
defenderse, verdad ? . . . solo puede salir corriendo si tiene algn problema :). Pues bien,
vamos hoy a ensearle a dar puetazos. Lo primero que necesitamos es el FBX de las
animaciones de puetazos. Si le das un vistazo a los recursos que descargaste en el
primer tutorial, y que los puedes descargar de aqu si an no los tienes, vers los
siguientes FBX:
MontageExample_Start.FBX: Animacin de inicio del movimiento del puetazo
MontageExample_Punch_1.FBX: Animacin del puetazo con el brazo derecho
MontageExample_Punch_2.FBX: Animacin del puetazo con el brazo izquierdo. Esta
animacin est hecha como continuacin de la anterior, con el objetivo de poder
mantener al personaje dando golpes alternando derecha / izquierda sin parar.
MontageExample_End_1.FBX: Animacin de fin del puetazo con la mano derecha
MontageExample_End_2.FBX: Animacin de fin del puetazo con la mano izquierda.
Estos recursos que estamos usando son de unos geniales video-tutoriales que prepar el
equipo de Epic Games y los puedes ver aqu. Nosotros los hemos tomado prestados para
nuestros tutoriales, pero tienen un problema, estas animaciones de puetazos NO son
hechas para el esqueleto de nuestro personaje, lo que implica que al reproducirlas,
nuestro hroe se deformar ligeramente, vers que por ejemplo se le separan un poco las
extremidades, esto no es un problema para el desarrollo de este tutorial, pero te lo

comento para que no pienses que estas haciendo algo mal :) . . . simplemente no
tenemos un animador en disposicin de estos tutoriales, por eso estamos usando los
recursos que podamos igual, para aprender y jugar con el UE4 vienen de maravilla :)
Importa estos FBX al proyecto dentro de la carpeta Animation o donde prefieras. Ya
sabes, en el Content Browser, Import/Seleccionas los FBX. En la ventana de Import del
UE4 selecciona Animation y el esqueleto que usa nuestro personaje y da clic en el
Botn Import. Listo, ya tenemos los recursos necesarios, puedes darle doble clic a cada
una de las animaciones importadas para que les des un vistazo en el Persona Editor.
Vamos a aprovechar esta situacin en la que tenemos una animacin en partes para dar
una rpida introduccin al Animation Composite, uno de los assets de animacin que
nos brinda el Unreal Engine 4.
Introduccin al Animation Composite en Unreal Engine 4
Animation Composite es un animation asset que nos permite unir ms de una animacin
una detrs de la otra y tratar esta secuencia de animaciones como una sola animacin.
En este ejemplo lo vamos a usar para unir las animaciones MontageExample_Start,
MontageExample_Punch_1 y MontageExample_End_1 en una sola animacin.
En el Content Browser selecciona: New/Animation/Animation Composite, selecciona el
esqueleto de nuestro hroe y ponle de nombre PunchAnimComposite. Dale doble clic
para editarlo.

En el panel de configuracin tenemos tres secciones, la primera es la seccin


Composite. Desde esta seccin haremos la composicin de la animacin, arrastrando
hasta aqu las distintas animaciones que formarn la secuencia final.

Las otras dos secciones (Notifies y Curves) no las veremos en este tutorial, pero sobre
todo los Notifies son sper tiles, nos sirven para definir eventos en puntos exactos de
la animacin y que podemos usar desde el Blueprint para implementar alguna funcin
determinada en ese preciso momento. Por ejemplo, reproducir un efecto de sonido
cuando la animacin est en el punto exacto en donde el pie toca el piso y as logramos
sincronizar el efecto de sonido de los pasos a la animacin de caminar.
Arrastra desde el Asset Browser las animaciones MontageExample_Start,
MontageExample_Punch_1 y MontageExample_End_1 a la seccin Composite. Fjate
que se crean dos filas y las animaciones se agregan alternadamente entre una y la otra
fila para facilitar la visualizacin. Con los controles de reproduccin puedes ver como
queda la composicin de esas tres animaciones en una sola.

Este nuevo asset de animacin que tenemos lo podemos usar como un


AnimationSequence normal. Vamos a ver un ejemplo simple. Ir por este proceso sin
detenernos mucho ya que es algo que a estas alturas no debes tener problema en
entenderlo si has seguido los tutoriales anteriores. Sino, te recomiendo que les des un
vistazo primero para que entiendas bien todo lo que haremos aqu.
Primero, desde Edit/Project Settings/Input, agrega una nueva entrada de tipo Action dale
de nombre Punch y selecciona la tecla R.

Abre el Blueprint del Character y crea una nueva variable de tipo bool de nombre
IsPunching. Esta variable estar en true cuando el usuario toque la tecla R y en false
cuando la suelte. Para lograr esto, abre el Event Graph del Blueprint del Character y
agrega lo siguiente:

Hasta ahora, la programacin de todo lo que tena que ver con las entradas del usuario y
las acciones que se ejecutaban, y en general la lgica del character, las tenamos
implementadas desde C++. Para este tutorial quise hacer esto por aqu para mostrarte la
variante blueprint, yo en lo personal este tipo de cosas las prefiero hacer en C++, pero
es a gusto de cada cual . . . despus me dices cual prefieres t ;)
Como vez, desde el blueprint podemos agregar un nodo que representa al evento
Pressed/Released de cada uno de los inputs que tenemos configurados. Cuando el
usuario toque la tecla R (que es la tecla que definimos para el Input de nombre Punch)
se va disparar este Evento en el blueprint por el puerto del Pressed, cuando la suelta se
dispara de nuevo por el puerto del Released.
Simplemente lo que hacemos es darle valor de true a la variable IsPunching cuando se
presione la tecla R y de false cuando se suelte.
Ahora abre el AnimationBlueprint del Character, agrega una nueva variable con el
mismo nombre, isPunching tambin de tipo bool. No es necesario que la variable tenga
el mismo nombre pero creo que es ms claro.
Modifica el Event Graph del AnimationBlueprint del Character para que te quede de la
siguiente forma:

Recuerda que este algoritmo se ejecuta constantemente en cada update del Animation.
Muy bien, ahora pasa a la maquina de estado que tenemos para el Character y
modifcala para que te quede de la siguiente forma:

Nada nuevo aqu tampoco, con esto acabamos de darle un nuevo estado al personaje
(Punch), a este estado entrar cuando est golpeando y al terminar de golpear volver al
Idle/Walk. Al agregar el nodo PunchAnimComposite al Final Animation Pose dentro del
estado Punch, asegrate de desmarcar la opcin de Loop, ya que no queremos que esta
animacin se reproduzca en loop.
Compila y ejecuta el juego:

Vale, esto a primera vista se ve bastante bien, pero con este mecanismo tenemos varios
problemas. Primero, al tenerlo como un estado en el Locomotion State Machine del
personaje, solamente se podr reproducir la animacin del golpe en cada momento. No
podr fusionar dos animaciones. Por ejemplo, si queremos que pueda golpear en lo que
camina tendremos un problema. Prueba para que veas, camina, y en lo que te desplazas
toca la R para golpear, vers como se reproduce la animacin del golpe pero en ese
momento se estar desplazando por el escenario patinando. Como nico pudiramos
solucionar esto es cancelando el desplazamiento cuando se est moviendo, aunque no es
una mala idea, no es lo que queremos hacer, queremos algo mas cool !! :)
De cualquier forma, creo que este simple ejemplo ha servido para ver el Animation
Composite que en muchos casos nos puede ser til. Pero este no es el plato fuerte de
este tutorial, vamos con algo mucho ms genial que nos brinda el UE4 y es el
Animation Montage.
Introduccin al Animation Montage en Unreal Engine 4
El AnimMontage es un animation asset que nos otorga una libertad fenomenal para el
trabajo con animaciones. Con este tipo de asset podemos exponer el control de la
animacin hacia el Blueprint, permitindonos en cualquier momento, pausar la
animacin, reproducir una seccin determinada de la animacin, definir al vuelo que
animacin se va a reproducir despus de la actual, saltar a reproducir otra animacin,
loopear de forma sper simple un grupo de animaciones y disparar eventos en cualquier
punto de la animacin, semejante a los Notifies. En fin, nos da un control total de las
animaciones a nivel de cdigo (ya sea C++ o VisualScripting).

En este ejemplo usaremos un AnimMontage para configurar las animaciones


relacionadas con los puetazos del personaje, ya que en el proceso de golpear tenemos
que tener total control de la animacin en cada momento.
En el Content Browser dentro de la carpeta Character da clic en
New/Animation/AnimMontage, selecciona el esqueleto que usa nuestro personaje.
Ponle de nombre PunchingAnimMontage y dale doble clic para editarlo.

El panel de configuracin del AnimMontage es algo parecido al AnimComposite. La


primera seccin es Montage, aqu es donde agregaremos todas las animaciones que
conformarn el AnimMontage, pero a diferencia del AnimComposite, estas animaciones
no tienen que ser una secuencia. La idea es que sean animaciones relacionadas a una
accin determinada pero que no precisamente las reproduciremos una detrs de otra,
sino que podremos crear secciones para seleccionar en cada momento que animacin o
animaciones reproducir.
Primero tenemos que definir un Slot Name para este AnimMontage. En el campo Slot
Name que tiene el alert en rojo Please provide a slot name for this asset escribe
PunchSlot
Arrastra desde el Asset Browser hasta la seccin Montage las animaciones
MontageExample_Start, MontageExample_Punch_1, MontageExample_Punch_2,
MontageExample_End_1 y MontageExample_End_2. Las animaciones se agregan
alternndose la fila para facilitar la visualizacin.

En este punto, si pre-visualizas la animacin, esta no tiene mucho sentido. Se


reproducen todas estas animaciones en secuencia, cuando no son una secuencia en
realidad. Pues bien, el AnimMontage nos permite, a partir de secciones que definamos,
hacer una mezcla entre estas animaciones y despus decidir cual vamos a reproducir en
cada momento.
Ahora vamos a crear las secciones que tendr este AnimMontage. En la primera fila del
panel Montage da clic derecho y selecciona New Montage Section y ponle de nombre
PunchStart. Fjate que se agrega una lnea verde clara vertical y en la primera fila se
muestra el nombre de esta seccin. Ahora, por defecto tenemos una seccin de nombre
Default al inicio del grfico, pon el cursor sobre la lnea verde que representa el inicio
de esa seccin Default y arrstrala hacia delante de la seccin PunchStart que acabamos
de crear, vers que automticamente la seccin PunchStart se posiciona en el inicio.
Ahora puedes dar clic derecho sobre esta seccin Default y eliminarla, ya que no la
vamos a usar.
Crea una nueva seccin y llmala Punch1 arrastra la lnea verde de esta seccin para
que quede exactamente en la unin entre las animaciones PunchStart y Punch1. Notars
que con la rueda del mouse puedes hacer zoom en esta grfica para ver bien la unin
entre las dos animaciones, tambin notars que el Editor te ayuda a posicionar la
seccin en la interseccin de dos animaciones.
Repite el proceso creando 3 secciones ms de nombre Punch2, PunchEnd1 y
PunchEnd2 y posicinalas al inicio de la animacin que le corresponde. Lo que
acabamos de crear aqu son las distintas secciones que componen el animation montage.
Te quedar de la siguiente forma:

Ya tenemos las secciones que conforman nuestro AnimMontage solo nos falta el ltimo
paso: Configurar la relacin entre cada una de las secciones. Fjate que debajo de la
zona Montage tienes la zona Sections con dos botones Create Default y Clear. Primero
da clic en el botn Clear para restaurar cualquier configuracin que tomen por defecto
las secciones. Debajo de estos botones tendrs la lista de botones alineados
horizontalmente que representan cada una de las secciones que acabamos de crear y
debajo de esos botones tendremos finalmente como relacionaremos cada una de las
secciones. Despus de dar en el botn Clear tienes 4 fila que representan cada una de las
secciones en donde ninguna seccin tiene relacin con otra.
Vamos a modificar esto, vamos conformar la primera seccin a partir de la animacin
PunchStart despus de reproducirse PunchStart queremos que seguidamente se
reproduzca Punch1 para lanzar el puetazo con la mano derecha. Bien, vamos a hacer
esto hasta aqu.
Primero da clic en el botn verde que dice PunchStart de la primera fila, debajo del
botn Preview All Sections, notars que se pondr en amarillo ahora toca de los botones
alineados horizontalmente arriba, el de nombre Punch1. Vers que automticamente se
agrega el Punch1 a continuacin del PunchStart. Te quedar as:

Muy bien, ahora vamos a complicar un poquito ms la estructura de esta seccin.


Cuando el personaje est dando puetazos lo que queremos es que si se deja la tecla R
presionada el personaje contine dando golpes indistintamente con la mano derecha y la
izquierda. Muy bien, pues para esto tenemos que crear un ciclo entre estas dos
animaciones Punch1 y Punch2. O sea que el proceso completo sera Punch Start ->
Punch 1 -> Punch2 -> Punch 1 -> Punch2 y as.
Toca en el botn Punch1 de la primera fila debajo del botn Preview All Sections , se te
pondr en amarillo. Ahora toca de los botones alineados horizontalmente arriba el de
nombre Punch2. Vers que automticamente, al igual que con el caso anterior, se te
agrega el Punch2 a continuacin del Punch1.
Ahora solo nos queda definir para que estas animaciones se mantengan reproducindose
en ciclo. Pues para esto es tan simple como tocar el botn Punch2 de la primera fila
debajo del botn Preview All Sections, cuando se ponga en amarillo toca de los botones
alineados horizontalmente arriba, el de nombre Punch1, vers como a diferencia de
antes que se agregaba a continuacin, ahora se ponen Punch1 y Punch2 en azulitos. Lo
que quiere decir que estas dos animaciones se van a reproducir en ciclo. La
configuracin de la primera seccin te quedar as:

Con esto terminamos de configurar las secciones que componen nuestro


PunchingAnimMontage. Fjate que puedes dar en el botn Preview al inicio de cada fila
para que veas la pre-visualizacin de cada seccin. Las dos ltimas secciones las
queremos as de simples, con una sola animacin, ya que las usaremos para llamar a una
de las dos, dependiendo en el punto en el que el jugador deje de presionar la tecla R,
para empatar el medio del puetazo con el final de este para el brazo correcto.
Perfecto ! Ya tenemos listo el PunchingAnimMontage compila y guarda los cambios.
Ahora hay que modificar el Animation Blueprint de nuestro personaje para que use este
Montage.
Primero abre el Locomotion State Machine del personaje y elimina el estado Punch que
creamos para ver el ejemplo del AnimComposite. Ahora, abre el AnimGraph, en este
momento nuestro AnimGraph tiene el nodo de la maquina de estado conectado
directamente al Final Animation Pose. Pues bien, para reproducir animaciones desde el
cdigo usando AnimMontage necesitamos un nodo especial en el AnimGraph, un nodo
de tipo Slot. Da clic derecho en el AnimGraph y selecciona dentro de la seccin
Blends, Slot (No slot name). Esto agregar un nodo de tipo Slot al AnimGraph. A este
nodo tenemos que decirle que AnimMontage representar y para esto basta con
seleccionarlo y en el panel de propiedades darle el mismo nombre que pusimos en el

campo Slot en el PunchingAnimMontage cuando lo creamos, que fue: PunchSlot. Ahora


conecta el StateMachina al Slot y este al Final Animation Pose. Listo !! , te quedar as:

Muy bien, ahora pasa al EventGraph y modifcalo para que te quede de la siguiente
forma:

Vamos a analizar lo que hemos hecho aqu, aunque estoy bastante seguro que si has
seguido los tutoriales anteriores no tendrs ningn problema con entender esto. Desde el
EventGraph podemos usar varios nodos para trabajar con los AnimMontage. En este
caso usamos dos de ellos. El Montage Is Playing que nos permite saber si se est
reproduciendo alguna animacin de las que estn en un AnimMontage y Montage Play
que nos permite reproducir un AnimMontage determinado. Al usar el Montage Play se
reproduce la primera seccin que tenemos definida en el AnimMontage, lo que quiere
decir, que en este caso cuando llegue aqu se va a producir la secuencia PunchStart>Punch1Punch2.
En el algoritmo lo que hacemos es determinar el valor de IsPunching, si este est en true
preguntamos si se est reproduciendo el PunchingAnimMontage, fjate que el segundo
puerto (o parmetro) de este nodo, nos permite definir a que AnimMontage nos
referimos. Entonces, si no se est reproduciendo es que vamos a reproducir el
PunchingAnimMontage. Aqu igual, el parmetro Montage To Play nos permite definir
que AnimMontage reproducimos, incluso nos permite indicar una velocidad de
reproduccin mediante el parmetro In Play Rate.
Esta validacin del Montage Is Playing la hacemos porque recuerda que este algoritmo
se reproduce en cada update del proceso de animacin del personaje, y en el tiempo en
el que se reproduce cualquiera de las secciones que tenemos definidas en el

PunchingAnimMontage este algoritmo se ejecuta ms de una vez. Si no hacemos esto,


en todo momento estaramos interrumpiendo la animacin para comenzarla de nuevo.
Compila, guarda, ejecuta el juego, y toca la tecla R. Perfecto !!, ya nuestro personaje
est dando puetazo como un loco, fjate que comienza la animacin del puetazo y
despus se queda alternando entre el golpe con la mano derecha y con la izquierda. Pero
tenemos un problema, a pesar de soltar la tecla R nuestro hroe se queda como loco sin
dejar de lanzar puetazos.
Si analizas lo que hicimos, tiene lgica que esto pase, recuerda que el Montage Play
lanza la reproduccin de la primera seccin que tenemos definida en el AnimMontage, y
la primera seccin que tenemos en el PunchingAnimMontage no termina, porque
despus del PunchStart entra en un loop entre Punch1 y Punch2 y de ah no sale nunca.
Pues bien, vamos a solucionar esto.
Recuerdas que tenemos adems de esa primera seccin en el PunchingAnimMontage
dos secciones ms no? PunchEnd1 y PunchEnd2 que son la animacin del terminado
del puetazo para la mano derecha e izquierda respectivamente. Pues bien, vamos a
usarlas, pero tenemos un problema, cmo saber cuando el usuario suelta la tecla R
exactamente que mano es la que est lanzando el golpe, para a partir de ah reproducir la
correspondiente animacin de fin del golpe segn la mano y terminar le proceso de
puetazo ? Pues aqu es donde entra a ayudarnos otra genial funcionalidad del
AnimMontage, los Brach Points.
Configurando los Branch Points en el PunchingAnimMontage
Branch Points es la forma que tenemos de lanzar eventos que podemos capturar en el
cdigo en puntos exactos de cualquiera de las animaciones que forman parte del
Montage, son similares a los Notifies solo que los Notifies son asincrnicos y los Brach
Points son sincrnicos. Esto quiere decir que estos ltimos tienen ms precisin en el
tiempo que los Notifies, pero por supuesto, requieren de ms procesamiento.
Abre el PunchingAnimMontage y en la cuarta fila del grafico en la seccin Montage,
debajo de la animacin Punch1, da clic derecho/ New Branch Point y ponle de nombre
IsPunching1. Ahora arrastra este branch point para colocarlo casi al final de la grfica
del Punch1. Repite el proceso para agregar otro branch point de nombre IsPunching2
debajo de la animacin Punch2 y colcalo casi al final de la grfica de esta animacin.
Te quedar de la siguiente forma:

Esto que acabamos de hacer nos permitir ejecutar un cdigo determinado en el


Blueprint inmediatamente que la reproduccin de la animacin pase por este punto. O
sea, que cuando el personaje est reproduciendo la animacin del puetazo, casi al
terminar la animacin del brazo derecho se va a lanzar el evento IsPunching1 y cuando
est terminando con el brazo izquierdo se va a lanzar el evento IsPunching2.
Ahora lo que necesitamos es intervenir estos eventos y preguntar si IsPunching est en
false, o sea si el usuario ya solt la tecla R, y si es as, actualizamos para que al terminar
esa animacin pase a reproducir la animacin de fin segn el brazo que sea.
Abre el EventGraph del AnimationBlueprint del personaje. En un espacio en blanco da
clic derecho y con el check Context Sensitive marcado fjate que tienes una seccin que
dice Add Montage Branching Point Event y esta seccin lista los dos branch points que
acabamos de crear. Agrgalos los dos al blueprint y continua modificndolo para que te
quede de la siguiente forma:

Para el trabajo con Montage desde el blueprint tambin contamos con el nodo Montage
Set Next Section. Este nodo nos permite definir cual es la siguiente seccin que se va a
reproducir despus que termine una determinada. Con el parmetro Section Name to
Change definimos cual es de la que vamos a partir, en cada caso segn el evento, ser
Punch1 o Punch2 y con el parmetro Next Section definimos la siguiente seccin que se
va a reproducir, que igual, segn sea el evento sera PunchEnd1 o PunchEnd2.
Tambin contamos con el nodo Jump Tu Section, que nos permite exactamente en ese
momento interrumpir la animacin que se est reproduciendo y reproducir otra seccin.
Listo, guarda, compila y ejecuta el juego. Toca la tecla R indistintamente, prueba tocarla
y dejarla unos segundos y despus soltarla. Notars que cuando se suelta la tecla R
segn la mano en la que se qued dando el puetazo es la que se usa para terminar la
animacin del puetazo genial, verdad !!??
Vale, pero an nos va quedando un problemita. Si intentas caminar en lo que ests
dando golpes vers que patinas en vez de caminar. Como dijimos, esto lo podemos

solucionar simplemente eliminado la posibilidad de caminar cuando se est dando


golpe, pero eso no es lo que queremos en nuestro juego, en nuestro juego queremos
poder salir corriendo sin parar y dando puetazos de todos colores :)
Pues bien, para lograr esto tenemos que usar en el AnimGraph un nodo sper til que se
llama Layered blend per bone. Este nodo nos permite fusionar distintas animaciones en
una, pudiendo definir que una parte del esqueleto reproduzca una animacin y la otra
parte otra animacin. Es esto exactamente lo que necesitamos, queremos que la
animacin del puetazo se reproduzca en la parte de arriba del esqueleto y la de caminar
en la parte de abajo.
Abre el AnimGraph del AnimationBlueprint del personaje. Ahora mismo lo tenemos
configurado de la siguiente forma:

Da clic derecho en una zona en blanco y agrega el nodo de nombre Layered blend per
bone. Por defecto este nodo solo tiene un puerto de entrada de nombre Base Pose y otro
de salida. Selecciona el nodo, da clic derecho sobre l, y despus da clic en Add Blend
Pin. De esta forma agregamos un segundo puerto de entrada al nodo.
Muy bien, pero si te fijas tenemos un problema. Nosotros en este visualscript en la
salida del StateMachine tenemos la animaciones de locomocin del personaje, y en la
salida del PunchSlot tenemos la animacin del puetazo, pero Layered blend per bone
necesita tambin como parmetro lo que nos retorna el StateMachine en limpio. Por
tanto, necesitamos el StateMachine conectarlo a dos puertos de entrada y sin embargo
este tiene un solo puerto de salida y no lo podemos duplicar. Bien, solucionar esto es
muy simple. Tenemos que usar un nodo que nos permite guardar en memoria (en cach)
la salida del StateMachine y este nodo si lo podemos duplicar todas las veces que
queramos en el blueprint.
Usando el nodo Save Cache Pose para guardar en cach el resultado del
SateMachine y poder usarlo varias veces en el blueprint.
En un espacio en blanco del blueprint da clic derecho y con el check de Context
Sensitive marcado agrega un New Save cached pose dentro de la seccin Cached

Poses. Ahora conecta la salida del StateMachine a este nodo. Bien, ya tenemos en cache
el State Machine. Ahora vuelve a dar clic en una zona en blanco y con el check Context
Sensitive marcado, agrega Use cached pose HeroLocomotionCache. Este nodo es una
referencia a esa cach en donde tenemos la salida del StateMachine, y lo mejor que
tiene es que lo podemos duplicar todas las veces que necesitemos.
Crea un duplicado de este nodo y conecta uno de ellos al primer puerto de parmetro del
Layered blend per bone. El otro conctalo al PunchSlot y la salida del PunchSlot
conctala al segundo parmetro del Layered blend per bone. Por ltimo el Layered
blend per bone conctalo al Final Animation Pose. Te quedar el grfico de la siguiente
forma:

Muy bien, ahora solo nos falta definir en el Layered blend per bone cual va a ser la parte
del esqueleto que usaremos para dividir la animacin. Selecciona el Layered blend per
bone y en el panel de propiedades de este nodo en la seccin Config tiene la propiedad
Layer Setup que es un arreglo con un solo elemento. Despliega el elemento 0 y este
tambin es un arreglo con un solo elemento de nombre Branch Filters. En este punto,
Branch Filters no tiene ningn elemento. Da clic en el botn de + para agregar un
elemento y en la propiedad Bone Name escribe spine_01. Spide_01 es el nombre del
hueso que vamos a usar para el blend, puedes dar clic en el Modo Skeleton (en la
esquina superior derecha) para que veas la estructura del esqueleto, busca y selecciona
el spide_01 para que veas que hueso es y que parte del cuerpo controla.
Finalmente el AnimGraph te quedar de la siguiente forma:

Listo, compila, guarda y ejecuta el juego. Una cosa importante a mencionar y que
notars en cuanto tires el primer puetazo. Vers que el modelo del personaje se
deforma un poco, esto pasa por lo que hablamos al inicio, estas animaciones que
puetazos que estamos usando NO son para este esqueleto. Por supuesto que en nuestro
juego vamos a tener un animador que nos dar los FBX correctos para el esqueleto de
nuestro personaje :)
Ahora prueba correr y dar puetazos al mismo tiempo, vers que funciona a la
perfeccin, a medida que la parte inferior del personaje mueve los pies con la animacin
de caminando o corriendo la parte de arriba reproduce al puetazo. Tal como queramos.
Conclusin
Ya nuestro personaje tiene las habilidades de dar puetazos, as que ya se puede
defender. Vamos a dejar esta primera parte aqu, en la segunda parte de este tutorial
vamos a agregar a un enemigo para golpearlo, y entrenar un poco con l :), en cada
golpe el enemigo recibir dao y cuando su salud se termine morir. Eso nos permitir
dar una introduccin a los mecanismos de colisin que nos brinda el UE4, a los
mecanismo de dao, a como reproducir efectos de sonidos, veremos como usar los
geniales recursos que tenemos a la mano en el marketplace y varias cosas ms. No te lo
pierdas, puedes seguirme en Twitter (@nan2cc) para que ests al tanto.
Mientras, te recomiendo que le des un vistazo a la serie de video-tutoriales que te
coment al inicio: Introduction to Third Person Blueprint Game, y sinceramente de
donde tom la idea y los recursos para este tutorial :). Es en ingls, pero aunque no se te
de bien el ingls, despus de pasar por este tuto podrs entender muy bien todo. Adems
vers un ejemplo de uso de los Notifies que comentamos aqu. Te recomiendo no te lo
pierdas.

Hasta la prxima !!

Cmo causar dao a un personaje en


UE4 Parte 2
2014/11/22 por nan2cc 2 comentarios
En el tutorial pasado vimos una introduccin al AnimComposite y el AnimMontage en
Unreal Engine 4 y dejamos a nuestro personaje con las habilidades necesarias para dar
puetazos. En este tutorial vamos a usar esas habilidades para golpear a otro personaje,
causndole dao hasta que su salud llegue a 0 y muera.
Este simple ejemplo nos permitir ver varias cosas nuevas:
Introduccin a los mecanismo de colisin que nos brinda UE4
El uso del MarketPlace.
El uso del Construction Script en los blueprints
Cmo aplicar dao a un personaje
Introduccin al trabajo con efectos de sonido en Unreal Engine 4
Cmo reproducir un AnimSequence directamente desde cdigo
Como eliminar un Actor del nivel cuando ya no se va a usar ms
Y muchas cosas ms ;) as que, manos a la obra !!
Introduccin a los mecanismos de colisin 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 teora detrs 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 cmo responder a la colisin con los otros Object Types
de tres formas distintas: si lo Ignorar, si se superpondrn o si lo bloquear. Los
Object Types existentes son:
WorldStatic: Los Volmenes existentes en el juego, y los objetos estticos del nivel,
por ejemplo: Una piedra o una pared deben ser WorldStatic
WorldDynamic: Los Actores dinmicos (los que se mueven) a parte a los Pawn,
PhysicsBodies y Vehicles (que son Objet Type especficos). Seran 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 fsicos. El trabajo con objetos fsicos los veremos en
prximos tutoriales. Bsicamente son objetos que se les puede definir para que se

comporten fsicamente 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 tambin en prximos tutoriales y
de seguro te va a encantar jugar un poco con ellos. Bsicamente 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 protagnico 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 muvete hasta la seccin Collision y despliega la propiedad Collision Presets.

Blueprint del personaje en el modo Components donde se muestra la configuracin de


Collision del [ROOT] CapsuleComponent

Desde esta seccin podemos configurar el Object Type de este objeto y cmo
reaccionar a las colisiones con los otros elementos del juego. Fjate 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 seccin vers que todas
las propiedades estn bloqueadas y con una configuracin predefinida, prueba variar la
seleccin de Collision Presets a otro que no sea Pawn, notars que cambia la
configuracin. Por supuesto, siempre podemos seleccionar Custom y settear la
configuracin que queramos especficamente para cada Object Type.

La configuracin de colisin 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 colisin, 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 ms adelante)
Collision Enabled: Para responder a ambos tipos de colisiones: con simulacin fsica y
sin ella.
Debajo tenemos el Object Type para definirle a este elemento. En este caso es Pawn.
A continuacin 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 colisin, estos son:
Ignore: Ignorar completamente la colisin. 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 seccin 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 colisin con Overlap estos se traspasarn,
pero si la opcin Generate Overlap Event est en true, en el momento de la colisin se
generar un evento que podemos intervenir desde el Blueprint o C++ y ejecutar una
accin determinada. Veremos un uso de esto ms adelante. Adems de la opcin
Generate Overlap Events tenemos la propiedad Simulation Generate Hit Events. Este
check es semejante al otro pero lo usamos cuando el objeto es fsico. Habilita para que
se generen eventos de tipo Hit cuando el objeto fsico colisiona con otro. Veremos su
utilidad en prximos tutoriales.
Block: Con el objeto que se defina para que responda a la colisin con Block no podr
ser atravesado. En el caso de la cpsula de colisin del Pawn vers 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, fjate que las filas estn 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 bsicamente rayos invisibles que
podemos usar para determinar si algn objeto colisiona con ese rayo y tiene montn de
utilidades. Veremos uso de estos en prximos tutoriales.
Te recomiendo que le dediques un tiempo a revisar la configuracin de colisin para
cada uno de los Collision Presets y adems la configuracin de colisin para cada uno
de los componentes del personaje, otra configuracin importante a tener en cuenta y
entender es la del Mesh del personaje que usa como Collision Presets: CharacterMesh

Configuracin de las propiedades de Collision para el Mesh del personaje.

Muy bien, ya con esta teora de nuestro lado, podemos pasar a implementar la
funcionalidad para poder golpear al lanzar un puetazo. La lgica detrs de esto sera:
detectar cuando el puo 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, tambin
nos brinda acceso al MarketPlace, la zona en donde podrs encontrar una enorme
cantidad de recursos para tus proyectos, tus prototipos para aprender, etc. Es un lugar
que al menos todas las semanas deberas darle un recorrido para ver que te trae de
nuevo.
Introduccin al Marketplace
Para usar el Marketplace tienes que tener tu subscripcin vlida y el Unreal Launcher,
que si no lo tienes, lo puedes descargar haciendo clic en el editor en la barra superior en
el botn MarketPlace:

Una vez que abras el Unreal Launcher tendrs la pantalla de login. Pon tu usuario y
password y Bienvenido al paraso !! :)

Captura del Marketplace

Tmate unos minutos y revsalo, veras el montn de cosas que encontrars, de seguro lo
querrs bajar todo :) .. . . s, es verdad, no todo es gratis, de hecho, la mayora de las
cosas son de pago, pero vamos !! mira el precio y compralo con todo el trabajo que te
ahorrars, 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 descrgalo
(est marcado en rojo en la imagen anterior). El Animation Pack es un paquete con un
montn de animaciones con el mismo modelo que estamos usando en nuestros
tutoriales.
Despus de descargarlo, en la seccin de Library podrs tener acceso a todo lo que
descargues y desde ah lo podrs agregar al proyecto. Agrega el Animation Pack al
proyecto, vers que se te crear en el Content Browser una carpeta de nombre
AnimStarterPack y dentro de ella, todo el contenido de este paquete. Tmate 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 adems de las animaciones
ya importadas tendrs 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 rpido, porque si has seguido los tutoriales no
tendrs 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

Pasa ahora para la seccin Components y mueve el Mesh para que quede dentro de la
cpsula y en la direccin correcta

Modo Components del BlueEnemyBlueprint

Ahora pasa al modo Graph para abrir el Blueprint de este personaje y crale una
variables nueva de nombre Health y de tipo INT y en valor por defecto ponle 100. Fjate
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 puetazo 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
sper simple, solo con el estado Idle.

Maquina de estado muy simple para el BlueEnemyCharacter

Vamos a aprovechar esta situacin para poner otro ejemplo del recin 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 agrgale las
animaciones Hit_React_1, Hit_React_2 y Hit_React_3 que tenemos en el
AnimStarterKit. Configralo para que te quede de la siguiente forma:

HitAnimMontage que usaremos para reproducir aleatoriamente una animacin de


impacto en el personaje cada vez que reciba un puetazo.

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

Ya tenemos todo lo necesario para jugar un poco con este personaje medio monigote y
digo medio monigote porque bsicamente lo que har es estar en reposo, cuando reciba
un puetazo expresar su dolor reproduciendo una animacin y cuando su salud llegue a
cero morir.
Para poder ver bien las colisiones entre ambos personajes podemos usar un pequeo
truco. Abre el BlueEnemyBlueprint selecciona el modo Componentes, selecciona
[ROOT]Capsule Component y en el panel detalles muvete hasta la seccin Rendering
y desmarca la propiedad Hidden In Game. Has esto mismo para el personaje

protagnico. Esto nos ayudar a ver en tiempo de ejecucin esta cpsula 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 cpsula. 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 cpsula rompiendo el modo de desplazamiento de nuestro scroll-side.
Prubalo para que lo veas mejor. Para evitar esto, lo que hice fue agregar un Box
Component al personaje que encierre a la cpsula y las propiedades de colisin las
configuro igual a la cpsula, 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 muvete en direccin al BlueEnemy. Cuando los
dos componentes llegan a colisionar, ya no te puedes mover ms. Si recuerdas cuando
miramos la configuracin de colisin para la cpsula, 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 estn configurados como Block, aunque intentes seguir movindote en esa
direccin no podrs avanzar ms.

Bien, eso est perfecto. . . ahora, lanza un puetazo presionando la tecla R. Como
notars, no pasar absolutamente nada, y en este caso la mano traspasa el Mesh del otro
personaje. Tenemos que lograr detectar la colisin del puo del personaje con el Mesh
del enemigo. Para esto vamos a irnos por una solucin muy simple, pero suficiente para
nuestro juego. Dicho sea de paso, esta solucin fue tomada del los video-tutoriales de
Epic Games que te coment en el tutorial pasado y que aprovecho para recomendrtelos
de nuevo :)
Vamos a agregar dos esferas que estarn ancladas a los puos del personaje. Cuando se
detecte la colisin de una de esas esferas con el Mesh del otro personaje, es que estamos
golpendolo.
Agregando dos Sphere Components anclados a las manos del personaje para
detectar la colisin cuando se lance un puetazo.
Abre el Blueprint de nuestro hroe en el modo Components. Fjate que en el panel
Components encima de la jerarqua de componentes que forman parte de nuestro
personaje, hay un ComboBox que dice Add Component. Desde este combobox
podemos agregar nuevos componentes al personaje. Despligalo y selecciona una
Sphere, repite el proceso y agrega otra. Mueve las esferas para que queden ms o menos
sobre cada una de las manos del personaje, no te tiene que quedar perfecto esto es solo
temporal. Cmbiale 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 podrs modificar una misma propiedad en
ambos componentes al mismo tiempo. Muvete en el panel Details a la seccin
Rendering y desmrcale Hidden in Game. En la seccin 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

En este punto las esferas estn 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 puetazo.
Hasta ahora solo hemos usado la hoja Event Graph del blueprint del personaje, pero
como ya habrs notado, tambin contamos con una hoja en blanco de nombre
Construction Script. Todo algoritmo que programemos aqu mediante visualscript se
ejecutar en la construccin del objeto. Vendra jugando como el papel del constructor
de nuestra clase. Modifcalo para que te quede de la siguiente forma:

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 habamos hecho anteriormente pero desde
C++. Hacemos un AttachTo de un componente a otro, como mismo hicimos con la
cmara y el SpringArm en el segundo tutorial. El nodo Attach To nos permite anclar un
componente a otro y le podemos especificar tambin el Socket al que lo anclaremos.
Todo lo relacionado con los Sockets lo veremos en prximos tutoriales, de momento
vasta con saber que son puntos en el objeto que podemos usarlos para anclar otro objeto.
Fjate que en el parmetro 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 vers que los huesos de la mano se llaman
hand_l y hand_r .
El ltimo parmetro del nodo AttachTo es el Attach Type y nos permite definir mediante
tres valores de enum como se afectar la posicin y rotacin de este elemento respecto
al padre. En nuestro caso queremos que lo siga totalmente, as que selecciona la opcin
Snap to Target.
En este punto me gustara 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
creacin de los componentes y los Attach To los hacemos desde C++. Quise en este

tutorial hacerlo mediante blueprint para ver un ejemplo de esta va. 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, vers que ahora salen las
esferas ancladas perfectamente a las manos del personaje. Esto pas porque al compilar
se ejecuta el construction script y esta seccin de componentes se actualiza. Genial
verdad !?

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 colisin
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 tcnica que vamos a usar para detectar cuando
golpeamos al otro personaje, pero para hacer esto bien, tenemos que hacer una
modificacin en las propiedades de colisin 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 preguntars Porqu desmarcar esta
opcin 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 generaran el evento y si por ejemplo se pasa por al lado del personaje
aunque sea caminando, se disparara el evento. Como es lgico, no es esto lo que
queremos, solo queremos que se detecte el evento si se est golpeando. Por lo que
dinmicamente 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 fjate que tenemos dos BranchPoints que creamos en


el tutorial pasado. Ajusta la posicin de cada BranchPoint ms o menos a la mitad de la
animacin si no lo tienes as:

Si te fijas con el timeline de la animacin, cada evento se disparara 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 segn
corresponda la propiedad Generate Overlap Event de los PunchComponents.

Por ltimo, para que el evento se dispare, necesitamos habilitar el Generate Overlap
Event tambin en el otro personaje. Abre el BlueEnemyBlueprint en el Modo
Components selecciona el Mesh y mrcale 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.

Listo !! esto es todo lo que necesitamos para detectar la colisin. Vamos ahora a
implementar la lgica de lo que pasa en ese momento.
Causando dao 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 dao.
Desde el BlueEnemyBlueprint en el modo Components selecciona el Mesh y en el panel
de detalles muvete hasta la seccin Events. Fjate que esta seccin tiene un combobox
que dice Add Event, si lo despliegas se listan todos los eventos de este componente que
podemos usar desde cdigo.

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 dao al personaje cuando se


dispare el mtodo Begin Overlap en el Mesh.

Aqu viene lo interesante. Cuando se dispara el mtodo BeginOverlap en el Mesh se usa


el nodo Apply Damage para aplicarle un dao a este personaje. Este nodo es sper til,
espera como parmetro cual ser el actor al que se le aplicar el dao. En este caso es
este mismo actor, por lo que usamos la variable self. Adems, permite definirle un valor
numrico de dao, en este caso le pasamos directamente 20, pero pudiramos usar una
variable para darle el valor dinmicamente. Los otros tres parmetros son opcionales y
pueden resultar muy tiles. Event Instigator se usa para definir el Controller que causa
el dao. Damage Causer se usa para definir el actor que causa el dao, por ejemplo, en
nuestro caso pudiramos pasar como parmetro una referencia de nuestro personaje y
por ltimo, Damage Type Class nos permite definir una clase con propiedades
especficas para extender la informacin del dao aplicado.
Es importante en este punto aclarar que para poder usar el mtodo 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 seccin 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. Acrcate al otro personaje y lanza un
puetazo con la tecla R.

Captura del juego en ejecucin 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 puo con el Mesh del otro
personaje y en ese punto aplicamos un dao. . . pues bien, una de las ventajas que
tenemos al usar el mtodo Apply Damage es que al aplicar un dao se lanza un evento
que podemos intervenir para implementar toda la lgica cuando un personaje recibe el
dao.
Vamos a intervenir este evento en el blueprint e implementar todo lo necesario para
restar la salud del personaje segn el dao 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.
Introduccin al trabajo con efectos de sonido en Unreal Engine 4
La msica 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 msica. 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 filosofa del blueprint, del trabajo con
nodos, la asociacin de un nodo a otro etc, se pueden crear complejos efectos de sonido,
mescla entre efectos y muchas cosas ms 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 botn Import e importa estos tres ficheros.
Vers que se te muestran como Sound Wave. Puedes reproducir cada uno dando clic
derecho sobre l y seleccionando la opcin Play en el men que se despliega. Desde el
cdigo 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, podrs 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 sper bsico 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 seleccin mltiple. Con los dos Sound Waves
seleccionados abre el Sound Cue, da clic derecho en una zona en blanco y selecciona de
la seccin From Selected, la opcin 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.
Con esto acabamos de crear un Sound Cue que podemos manejar como un efecto de
sonido normal, pero al decirle que se reproduzca, l slo se encargar de seleccionar
aleatoriamente uno de estos dos efectos y reproducirlo. Sper verdad !! ?
Pues ya con esto estamos listo para retomar la implementacin de lo que pasa cuando el
personaje recibe el dao.
Interviniendo el evento Any Damage para implementar lo necesario cuando el
BlueEnemy recibe el dao por un puetazo.
Muvete a una zona en blanco del BlueEnemyBlueprint e implementa el siguiente
algoritmo

Algoritmo cuando el BlueEnemy recibe dao.

Muy bien, vamos con detenimiento por todo este algoritmo porque en l usamos varios
nodos que no habamos usado antes. Primero agregamos el Nodo Event Any Damage.
Este evento se dispara cuando este actor recibe dao. En este caso se disparara cuando
se detecta la colisin con el puo del personaje y se llama al Apply damage.
Fjate que desde este evento podemos obtener el valor de dao aplicado, recuerda que
en nuestro caso es 20, adems podemos obtener el Damage Type, el Instigate By y el
Damage Causer que como vimos, se pueden pasar como parmetros al Apply Damage.
Lo primero que hacemos es restarle la cantidad de dao 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 operacin la variable tome valor menor que 0 o
mayor que 100 en caso que fuera posible.
Despus 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, fjate que si intentas
conectar la variable Health al puerto B del Append, como son dos variables de tipo de
dato distinto, el editor automticamente 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.
Despus de eso tenemos una condicin usando el nodo Branch. Preguntamos si la
variable Health lleg a cero. Si es false, es que al personaje an le queda salud y en este
caso reproducimos una animacin simple para reflejar el golpe. Fjate 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 nmero aleatorio entre 1 y 3 creamos un string mediante el Append
uniendo el string HitReact con el nmero 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 animacin y le pasamos
por el parmetro 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 animacin aleatoria para reaccionar al golpe
Por ltimo reproducimos el Sound Cue que creamos hace unos minutos y que vimos
que sera aleatoriamente uno de los dos efectos de dolor. Para esto usamos el nodo Play
Sound at Location. Este nodo espera dos parmetros. El parmetro Sound que es el
archivo de sonido a reproducir puede ser directamente aun Sound Wave o un Sound
Cue, y el segundo parmetro nos permite definir la posicin en el mundo 3D en la que
se reproducir el sonido. En este caso le pasamos la posicin 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 animacin de muerte. Pero fjate que usamos un nuevo nodo para
reproducir una animacin. El nodo Play Animation nos permite reproducir un
AnimSequence directamente sin tener que hacer uso del AnimationBlueprint o de los
AnimMontage. El parmetro Looping tiene que estar en false, ya que queremos que esta
animacin se reproduzca una sola vez y quede ah en el ltimo frame.
Tambin reproducimos un efecto de sonido, en este caso un Sound Wave directo, solo a
modo de demostracin.
Por ltimo, hay un detalle. Si pruebas en este momento vers que todo va de maravillas
pero cuando tumbas al otro personaje con el ltimo golpe, este caer al suelo con su
animacin, pero se quedarn en el medio del camino los dos componentes de colisin, la
capsula y la caja. Para solucionar esto, seguido a la reproduccin 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 solucin
puede ser desactivarle la colisin, 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 despus de
tumbar al personaje pasaran tres segundos y su cuerpo desaparecer del nivel.
Listo !!, compila, guarda y ejecuta el juego. Muvete hasta donde est el otro personaje
y comienza a golpearlo. Vers que cada vez que le damos un puetazo lanza una de las
animaciones de impacto y cuando su salud llega a cero termina con la animacin 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 fijndote en que las animaciones cuando
el personaje recibe un golpe estn terribles, con la reaccin del personaje parece ms a
que le estn haciendo cosquillas :), pero son las animaciones que tenemos a mano :( . . .
ya en nuestro juego, que el equipo de animacin nos haga algo mejor :)

Captura del juego cuando el personaje le da el ltimo puetazo al enemigo y lo derriba.

Conclusin
Vamos terminando aqu este tutorial, espero que te hayas divertido dndole puetazos 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 ms soltura con el framework de clases del
Engine.
En el prximo tutorial vamos a comenzar a darle armamento a nuestro personaje y ha
poner ms accin en nuestro juego. Puedes estar al tanto siguindome en Twitter
(@nan2cc) . . . mientras, me encantara escuchar tus comentarios y si tienes algn tema
especfico del que quisieras un tutorial tambin djame un comentario, har todo lo
posible por complacerte ;) . . . hasta la prxima, bye !!

Implementando un inventario y usando un arma


en UE4
2014/12/15 por nan2cc 2 comentarios
En este tutorial crearemos un sistema de inventario para equipar armas e
implementaremos la lgica para poder recoger, recargar, disparar el arma y detectar con
qu colisiona el disparo. Esto nos permitir ver varios conceptos y tcnicas nuevas para
nuestro juego. En este tutorial veremos:

Introduccin a los Sockets, el mecanismo que nos brinda UE4 para


anclar un elemento a otro en un punto determinado.

Uso del AnimMontage para las animaciones al usar el arma.

Uso del LineTrace para detectar colisin con una lnea imaginaria. Con
el uso de este mtodo simularemos la trayectoria del disparo.

Implementaremos un sistema de inventario genrico para nuestro


juego, donde el personaje podr seleccionar, de las armas que tenga
disponible, cul usar.

Agregaremos los efectos de sonido al disparar y recargar el arma.

Veremos una introduccin a los AnimNotifies para lanzar eventos en


puntos exactos de una animacin.

Y muchas cosas ms, as que no te lo pierdas.

Preparando los recursos necesarios


Puedes descargarte de aqu los recursos que usaremos en este tutorial. Al descomprimir
el .zip encontrars varios efectos de sonidos para el arma y el FBX de una SPAS-12.
Aprovecho para decirte que el modelo de la SPAS-12 lo descargu de: tf3dm.com. En
ese sitio podrs encontrar montn de modelos 3D gratis, listos para importarlos en tus
proyectos de pruebas y prototipos, as que si con el MarketPlace no estas conforme, ah
te dejo otro lugar donde encontrar recursos ;).
Adems del modelo del arma y los efectos de sonidos, tambin est incluido en los
recursos las clases Weapon, SPAS12Weapon, HeroCharacter como quedarn al terminar
el tutorial, para una referencia ms rpida.
Importa todos estos recursos al proyecto. Es bueno que mantengas los elementos
organizados en el Content Browser, por ejemplo, puedes crear una carpeta de nombre
Weapons, dentro de ella, las carpetas particulares para cada tipo de arma que tengas en
tu juego. Dentro de cada una coloca todos los recursos que son de esta arma. Puedes
tambin crear dentro de esta carpeta, otra carpeta llamada Sounds, para tener ah los

efectos de sonido. En fin, organzalo como mejor sea para ti, pero siempre es bueno
tener el Content Browser bien organizado ;)
Despus que importes los .wav de los efectos de sonidos, crea los Sound Cue
correspondientes.
. . . Ya ?? . . . vale, comenzamos.
Introduccin a los Sockets en Unreal Engine 4
Nuestro personaje tendr la posibilidad de encontrar armas en el escenario, recogerlas y
equiparlas. Cuando recogemos un arma, tendremos que agregar el modelo del arma en
el guarda pistola del personaje, en este caso ser en la parte de atrs del cinturn. De
igual forma, cuando equipa el arma para usarla, la tendremos que anclar a la mano del
personaje. Pues bien, para este tipo de cosas Unreal Engine nos brinda los Sockets
Desde el Persona Editor podemos crear un socket en una posicin relativa a un hueso
del esqueleto. Estos sockets, que bsicamente son puntos invisibles, los podemos rotar o
trasladar relativos a la posicin del hueso en donde se ha creado y podemos anclar otros
objetos en esta posicin.
Por ejemplo, en nuestro caso lo que haremos ser crear dos sockets, el primero lo
crearemos relativo al hueso spine_01, para que quede justo donde nuestro personaje
guardar la escopeta. El segundo lo crearemos relativo a la mano del personaje, para
anclar el arma a este socket cuando la vaya a usar.
Creando los sockets necesarios en el esqueleto del personaje
Abre el esqueleto que usa nuestro personaje (HeroTPP) y en el panel Skeleton Tree
(esquina superior izquierda) tenemos la estructura de huesos del esqueleto, aqu se
muestra el rbol de huesos de este esqueleto. Selecciona el hueso spine_01, da clic
derecho y selecciona Add Socket y dale de nombre HolsterSocket, este nombre lo
usaremos desde programacin para poderle decir a la escopeta en que socket se va a
anclar cuando el personaje la recoja.

Captura del Persona Editor agregando el Socket relativo al hueso spine_01

Ahora da clic derecho sobre el HolsterSocket desde el Skeleton Tree, selecciona Add
Preview Asset y selecciona el StaticMesh de nuestra escopeta. Esto nos permite agregar
a este socket a modo de pre-visualizacin el objeto que finalmente anclaremos aqu. De
esta forma podemos ajustar la posicin y rotacin del HolsterSocket en base al punto de
pivote del otro objeto.

Agregando al HolsterSocket el StaticMesh de la SPAS-12, a modo de pre-visualizacin.

En este punto vale aclarar una cosa. Como notars, al anclar la escopeta aqu, el punto
de anclaje est en la culata de la escopeta, que es el punto de pivote del modelo. El
punto de pivote de un objeto en Unreal Engine 4 determina el punto sobre el que se har
cualquier transformacin (traslacin, rotacin o escala). Este punto de pivote siempre
est localizado en el origen (0,0,0) cuando se exporta el modelo desde el software de
modelado 3D. Para el caso de las armas, es buena idea antes de exportar el modelo,
garantizar que este punto de pivote est sobre el gatillo del arma, de esta forma evitamos
conflictos a la hora de colocar distintos modelos de armas en un mismo socket.
Puedes ver la posicin del punto de pivote de cualquier StaticMesh, abrindolo desde el
Content Browser y marcando en el Toolbar del StaticMesh Editor, el botn Pivot Point.
Muy bien, ahora necesitamos mover y rotar el socket para que la SPAS-12 quede en la
posicin correcta, ya teniendo la pre-visualizacin del modelo, es muy fcil ajustar la
posicin y rotacin correcta para el socket. Selecciona el HolsterSocket y con las
herramientas de rotacin y transformacin ve rotando y moviendo el socket hasta que la
SPAS-12 te quede en la posicin correcta.

Captura del Persona Editor despus de rotar y trasladar el HolsterSocket, dejando la


SPAS-12 en la posicin correcta

Un truco bastante til para lograr la posicin exacta es pre-visualizar la animacin que
tendr que ver con este socket, en este caso es la animacin de desenfundar la escopeta.
As puedes detener la animacin en frames determinados y mover o rotar el socket
teniendo como referencia la postura del personaje.
Muy bien, ahora crea un nuevo socket en el hueso hand_r (mano derecha) y dale de
nombre HandSocket. Agrega la pre-visualizacin de la SPAS-12 a este socket, y de la
misma forma que acabamos de hacer, traslada y rota el socket hasta que la escopeta
quede en la posicin correcta. Puedes cargar la animacin de Idle_Rifle_Hip para que el
preview del esqueleto se vea con esta animacin. De esta forma te ser ms fcil
posicionar el socket.

Captura del Persona Editor despus de configurar el HandSocket

Perfecto !!, ya tenemos listo los dos sockets que necesitamos en nuestro personaje.
Vamos ahora ha implementar la lgica de nuestra arma.
Implementando las clases Weapon y SPAS12Weapon
Vamos a implementar las clases para las armas. Tendremos una clase base llamada
Weapon, esta clase tendr la lgica comn para cualquier tipo de arma y ser una clase
abstracta, o sea, no podemos tener instancias de ella, solamente servir de clase base
para las armas especificas. Adems, tendremos la clase SPAS12Weapon que heredar de
Weapon y ser nuestra escopeta.
Crea una nueva clase que herede de Actor y nmbrala Weapon y crea otra clase que
herede de Weapon y nmbrala SPAS12Weapon.
Abre el archivo Weapon.h y modifcalo para que te quede de la siguiente forma:
1 #pragma once
2
3 #include "GameFramework/Actor.h"
4 #include "Weapon.generated.h"
5
6

/**

7 * Clase Base abstracta de todas las armas.


8 */
9 UCLASS(abstract)
class UE4DEMO_API AWeapon : public AActor

1
0{
1
1

GENERATED_UCLASS_BODY()

1
protected:
2
1
3

/**

1
* USphereComponent es un componente en forma de esfera
4 generalmente usado para detectar colisiones simples
* Este ser el Root del arma y con l detectaremos las
1
colisiones
entre el personaje y el arma
5

1
6
1
7
1
8

*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category =
"Weapon")
TSubobjectPtr<USphereComponent> BaseCollisionComponent;

/** StaticMesh del arma.

*/

1
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category =
9 "Weapon")
2
0
2
1
2
2

TSubobjectPtr<UStaticMeshComponent> WeaponMesh;

/** Cantidad mxima de municiones */


UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
int32 MaxAmmo;

2
3
2
4
2
5

/** Alcance del disparo */


UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
int32 ShotDistance;

2
6
2
7
2
8
2
9
3
0

/** Efecto de sonido del disparo */


UPROPERTY(EditAnywhere, Category="Sounds")
USoundCue* ShotSoundEffect;

/** Efecto de sonido cuando no hay municin */


UPROPERTY(EditAnywhere, Category="Sounds")
USoundCue* EmptySoundEffect;

3
1 public:
3
2
3
3
3
4

/** Cantidad de municiones actuales */


UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
int32 Ammo;

/** True cuando el arma est en el escenario y false cuando es


3
5 recogida por el Pawn */

3
6
3
7
3
8
3
9
4
0
4
1

bool bIsEquipped;

/**
* Es llamado desde el Pawn cuando colisiona y recoge el arma
* De momento solamente pone en true el flag bIsEquipped y
muestra un log en la pantalla
*/
void OnCollected();

/**
* Dispara el arma y obtiene el objeto que colision con el

4 disparo
2
4
3

* Mtodo abstracto para sobreescribir en las clases hijas segn


las caractersticas especificas del disparo de cada arma

*/

4
4

UFUNCTION(BlueprintImplementableEvent, Category="Weapon")

4
5

virtual void Fire();

4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6

/** Reinicia las municiones del arma */


void Reload();
};

1
6
2
6
3
6
4
6
5
6
6
6
7

Aqu lo nico nuevo que tenemos es el uso de UCLASS(abstract). As es como le


decimos al Engine que esta clase es abstracta. La clase Weapon est compuesta por los
siguientes atributos:
BaseCollisionComponent: Componente que usaremos como ROOT de este actor y
para detectar la colisin.
WeaponMesh: Mesh del arma y que cargaremos desde el Editor.
MaxAmmo: Mxima cantidad de municiones
Ammo: Cantidad de municiones disponibles, se decrementa con cada disparo.
ShotDistance: Alcance del disparo. Para la implementacin del disparo, como veremos
ms adelante, lo que haremos es lanzar un rayo imaginario una x distancia hacia delante,
el primer objeto que colisione con ese rayo ser el que reciba el disparo. Para variar un
poco el comportamiento entre las armas, el largo de ese rayo lo definiremos usando esta
variable, esto nos permitir definir un alcance especifico para cada arma.
ShotSoundEffect: Efecto de sonido del disparo de esta arma. Lo cargaremos desde el
editor.
EmptySoundEffect: Efecto de sonido cuando se intenta disparar el arma estando sin
municiones. Tambin lo cargaremos desde el editor.
bIsEquipped: Este ser un flag que usaremos para controlar que no se contine
detectando la colisin cuando el arma ya sea recogida por el Character. Como mismo
hicimos con las monedas en el segundo tutorial.

Adems de esto tenemos dos mtodos


OnCollected: Este mtodo ser llamado desde el Character cuando recoja el arma. Le
daremos una implementacin general aqu. Solamente lo usaremos para poner en true el
bIsEquipped y para imprimir un log en la pantalla. Si quisiramos hacer algo en
particular con cada arma en el momento en el que es recogida por el personaje, entonces
tendras que tener una implementacin especifica de este mtodo en las clases hijas.
Fire: En este mtodo estar toda la lgica cuando se dispara el arma, decremento de las
municiones, reproduce el efecto de sonido correspondiente y lanza el rayo para
determinar con que a colisionado el disparo. Es un mtodo virtual, que no tendr
implementacin en esta clase, sino que lo implementaremos segn el arma en
especifico. Es vlido aclarar que si en tu juego la lgica del disparo ser la misma entre
todas las armas, ya que puede ser el caso de que no tengas una gran diferencia del modo
de disparo entre las armas, puedes dejar la implementacin en esta clase base y que la
hereden todas las armas.
Reload: Este mtodo es llamado por el jugador cuando decide recargar el arma (tocando
la tecla R) y simplemente reinicia la cantidad de municiones disponibles con el valor de
MaxAmmo
Abre ahora el archivo Weapon.cpp y modifcalo para que te quede de la siguiente forma:
1 #include "UE4Demo.h"
2 #include "Weapon.h"
3
4
5 AWeapon::AWeapon(const class FPostConstructInitializeProperties&
PCIP)

: Super(PCIP)

7{
8

bIsEquipped = false;

9
1
0

//Crea la instancia del USphereComponent

BaseCollisionComponent =
1 PCIP.CreateDefaultSubobject<USphereComponent>(this,
1 TEXT("BaseSphereComponent"));

1
2

//Inicializa el RootComponent de este Actor con el

1 USphereComponent
3

RootComponent = BaseCollisionComponent;

1
4
//Crea la instancia del UStaticMeshComponent

1
5

WeaponMesh =
PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this,
1 TEXT("WeaponMesh"));

6
1
7

//Settea el Profile de collision del este objeto en OverlapAll


para que no bloquee al personaje

1
WeaponMesh8 >BodyInstance.SetCollisionProfileName(FName(TEXT("OverlapAll")));
1
9
//Agregamos el UStaticMeshComponent como hijo del root component

2
0

WeaponMesh->AttachTo(RootComponent);

2}
1
2 void AWeapon::OnCollected()
2
2
3

{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Weapon
Collected !!");

2
4
2
5}
2
6

bIsEquipped = true;

void AWeapon::Reload()

2
{
7
2
8}
2
9
3

Ammo = MaxAmmo;

0
3
1
3
2
3
3
3
4
3
5
3
6

En el constructor tenemos la inicializacin del RootComponent y el MeshComponent. A


estas alturas no debes tener problema con entender eso. Adems setteamos el profile de
colisin del arma en OverlapAll ya que usaremos el evento que se dispara al estar
haciendo overlap con la pistola para poder recogerla del escenario.
Tambin tenemos la implementacin de los mtodos OnCollected y Reload que son
sper simples.
Ahora vamos a implementar la lgica de nuestra escopeta. Abre el archivo
SPAS12Weapon.h y agrgale la declaracin del override para el mtodo Fire, te quedar
as:
1 #pragma once
2
3 #include "Weapon.h"
4 #include "SPAS12Weapon.generated.h"
5
6
7
8
9
10

UCLASS()
class UE4DEMO_API ASPAS12Weapon : public AWeapon
{
GENERATED_UCLASS_BODY()

11

virtual void Fire() OVERRIDE;

12 };

Pasa ahora a SPAS12Weapon.cpp y modifica su contenido para que te quede de la


siguiente forma:
1 #include "UE4Demo.h"
2 #include "SPAS12Weapon.h"
3
4
5 ASPAS12Weapon::ASPAS12Weapon(const class

FPostConstructInitializeProperties& PCIP)

: Super(PCIP)

7{
8

//Cantidad mxima de municiones para esta arma

MaxAmmo = 4;

1
0

//Cantidad de municiones para esta arma

1
1

Ammo = 4;

1
2
1
3

//Alcance mximo de la escopeta


ShotDistance = 5000;
}

1
4
void ASPAS12Weapon::Fire()

1
5{
1
6
1
7
1
8
1
9

//Si la escopeta an tiene municiones ...


if(Ammo > 0)
{
//HitResult de la primera colisin del trace
FHitResult OutHit;

//Punto inicial para el Trace. La posicin del FireSocket en


2
0 el Mesh de la escopeta
FVector TraceStart = WeaponMesh2
>GetSocketLocation("FireSocket");
1

2
2
2
3
2
4

//Punto final para el Trace. Otro punto en linea recta a


[ShotDistance] unidades de distancia
FVector TraceEnd = (WeaponMesh->GetRightVector() *
ShotDistance) + TraceStart;

//Parmetros adicionales usados para el trece, en este los


2
valores por defecto son suficiente.
5
FCollisionQueryParams TraceParams;

2
6

2
//Lanza un rayo desde TraceStart hasta TraceEnd, retorna true
7 si se encontr alguna colisin y en OutHit el HitResult de la primera
2
8

colisin
bool bHit = GetWorld()->LineTraceSingle(OutHit, TraceStart,
TraceEnd, ECC_Visibility, TraceParams);

2
9
3
0

//Si el rayo colision con algo ...

3
1

if (bHit)

//... Imprime en pantalla el nombre del Actor (a modo de

3 prueba)
2
3
3

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red,


OutHit.Actor->GetName());

3
//Dibuja una linea, a modo de Debug, desde la posicion
4 inicial hasta el punto de impacto
DrawDebugLine(GetWorld(), TraceStart, OutHit.ImpactPoint,
3
5 FColor::Red, false, 5.f);

3
6
3
7

//Dibuja un punto en la zona del impacto, a modo de


Debug.

DrawDebugPoint(GetWorld(), OutHit.ImpactPoint, 16.f,


3
8 FColor::Red, false, 5.f);

3
9

4
0

else //el rayo no colision con nada ...

//Dibuja una linea, a modo de Debug, desde la posicion

4 inicial hasta la final


1

DrawDebugLine(GetWorld(), TraceStart, TraceEnd,


FLinearColor::Red,
false, 5.f);
4

4
3
4 pistola
4
4
5

//Reproduce efecto de sonido del disparo en la posicin de la


if (ShotSoundEffect)
{
UGameplayStatics::PlaySoundAtLocation(this,

4 ShotSoundEffect, GetActorLocation());
6
}

4
7

//Decrementa la cantidad de municiones disponibles

4
8
4
9
5
0

Ammo--;
}
else //Si la pistola no tiene municiones ...
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Sin

5
municiones :(");
1
5
2
5
3

//Reproduce efecto de sonido de la escopeta vaca


if (EmptySoundEffect)
{

5
UGameplayStatics::PlaySoundAtLocation(this,
4 EmptySoundEffect, GetActorLocation());
5
5

5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7

}
}

3
7
4
7
5

En el constructor solamente necesitamos definir por defecto la cantidad de municiones y


el alcance del disparo, recuerda que de todas formas gracias al macro UPROPERTY,
estos valores los podemos modificar desde el editor, en la seccin Weapon, en el panel
de propiedades de este objeto. Adems, tenemos el mtodo estrella de nuestra arma :), el
Fire. Vamos paso a paso con lo que hacemos en este mtodo:
Primero tenemos que comprobar que el arma tenga municiones, si es as, preparamos
los parmetros que usaremos en el mtodo GetWorld->LineTraceSingle. Este mtodo
nos permite lanzar un rayo invisible desde un punto a otro, nos retorna si se detect
alguna colisin con l y por referencia en la variable OutHit viene toda la informacin
del primer Hit, encapsulada en la estructura FHitResult. Puedes ver la implementacin
de esta estructura en los fuentes del Engine para que tengas una idea de toda la
informacin que tenemos del impacto. De momento solo nos interesa el Actor con el
que se ha colisionado.
El mtodo recibe como parmetros la variable OutHit (de salida), adems los vectores
de inicio y fin del rayo. Aqu vamos a detenernos para ver de que forma armamos este
rayo. Si lo que queremos es un rayo que simule la trayectoria del proyectil, el primer
punto que necesitamos estara en el can de la escopeta y el otro punto lo necesitamos
alineado a este punto, en la direccin del can, una x distancia por delante. Acordamos
que esta distancia la bamos a definir mediante la variable ShotDistance, para tener la
posibilidad de variar el alcance de cada arma.
Muy bien, pero tenemos un problema. Como obtenemos el punto exacto en la salida del
can de la escopeta ? . . . se te ocurre algo ? . . . pues claro !!, mediante un socket. Los
Sockets no solo los podemos crear en un esqueleto, tambin los podemos crear en un
StaticMesh. Adems, este socket no solo nos servir para saber este punto, tambin nos
puede servir, por ejemplo, para en el momento del disparo anclar y emitir desde aqu un
sistema de partculas para simular el efecto de humo y fuego del arma al dispararse. An
no hemos visto los sistemas de partculas en estos tutoriales, pero un muy buen ejercicio
investigativo es que busques por tu cuenta un poco de informacin sobre estos e intentes
acoplar aqu ese efecto en el momento del disparo. Despus me encantara que nos
dejaras tu solucin en los comentarios y la agregamos al tutorial como complemento ;)
Muy bien, si te fijas en el cdigo, para obtener el punto inicial del rayo lo hacemos a
partir de la lnea WeaponMesh->GetSocketLocation(FireSocket). El mtodo
GetSocketLocation nos retorna la posicin del socket con el nombre pasado como

parmetro. Por supuesto, este socket tiene que existir en el Mesh. Vamos entonces al
editor para configurar este socket en el StaticMesh de nuestra escopeta.
Abre el StaticMesh de la escopeta. En el Toolbar del Static Mesh Editor, hay un botn
para activar o desactivar la pre-visualizacin de los sockets, asegrate de tenerlo
activado. Desde el men principal del Static Mesh Editor selecciona Window/Socket
Manager. Esto te agregar en la esquina inferior derecha del editor, debajo del panel
Details, el panel Socket Manager. Desde este panel podrs agregar y configurar sockets
a este StaticMesh prcticamente de la misma forma que hicimos con el esqueleto del
personaje.
Selecciona el botn Create Socket, dale de nombre al nuevo socket FireSocket y
muvelo para posicionarlo en la punta del can.

Captura del Static Mesh Editor con el modelo de la escopeta y con el FireSocket en la
posicin correcta.

Listo !!, guarda y cierra el editor. Regresamos al cdigo del mtodo Fire para seguir
analizndolo. Ya tenemos el punto de inicio del rayo, ahora nos falta el punto final. El
tercer parmetro que recibe el mtodo es el punto final del rayo y este lo obtenemos
gracias a unos mtodos sper tiles que tenemos para los Mesh, son los mtodo
GetForwardVector, GetRightVector, GetUpVector. Estos mtodos nos retornan un vector
unitario en cada una de las direcciones del Mesh. En este caso necesitamos el mtodo
GetRightVector que nos da un vector unitario en la misma direccin del can. Con este

vector y un poco de matemtica muy simple, conseguimos nuestro punto final. Para
obtener el punto final necesitamos multiplicar este vector por el valor que queremos
para la distancia del disparo, en este caso guardado en la variable ShotDistance, y el
resultado lo sumamos al vector inicial. Esta operacin nos dar el punto final del rayo
con el que vamos a simular la trayectoria de la bala.
El cuarto parmetro del LineTraceSingle es el canal que usar este rayo para detectar
las colisiones. Recuerdas que en el tutorial anterior vimos una introduccin a las
colisiones en Unreal Engine 4 y que hablamos de los Collision Responses de cada
objeto y que se dividan en dos grupos: los Trace Responses para las colisiones con
rayos, como es el caso, y los Object Response para las colisiones con otros objetos.
Recuerdas ? pues bien, este parmetro permite definir que tipo de Trace Response
usar el rayo, en este caso indicamos Visibility. Si le das un vistazo a cualquier objeto
en la seccin Collision vers que para los Trace Response existen dos opciones
Visibility y Camera. Una cosa muy importante, los objetos que puedan recibir un
disparo, o sea, que este rayo pueda colisionar con ellos, tienen que tener marcado en
Block el Trace Response: Visibility, ya que este es el canal que estamos usando para
este rayo. De lo contrario, aunque visualmente notemos que el rayo colisiona, no se
detectar la colisin.
El ltimo parmetro son opciones adicionales que podemos usar para el rayo, de
momento con sus valores por defecto tenemos suficiente. Puedes revisar la
implementacin de esta estructura para que veas los atributos que tiene.
Al llamar al mtodo LineTraceSingle, en la variable bHit tendremos si se colision con
algo o no, y en la variable OutHit tendremos la informacin del primer hit. Con esto, lo
nico que nos queda es comprobar si bHit es true, si es as, imprimimos un mensaje en
la pantalla con el Nombre del objeto con el que colision el rayo y adems con la ayuda
de los mtodos DrawDebugLine dibujamos, a modo de debug, una lnea para poder ver
la trayectoria del disparo y validar que todo est funcionando como tiene que ser.
En prximos tutoriales vamos a determinar en este punto, si la colisin con el disparo a
sido con un enemigo, y en ese caso le aplicaremos un dao, aunque los mecanismos
para aplicar dao ya los hemos visto en tutoriales anteriores, y sera sper bueno que te
adelantes e implementes esto por tu cuenta.
En caso que bHit est en false, es que no se detect colisin con ningn objeto, esto
puede pasar porque no hay ningn objeto en el trayecto del disparo, al menos a una
distancia menor que ShotDistance. En ese caso tambin imprimimos en pantalla un
texto temporal y dibujamos una lnea a modo de debug.
Despus de esto, si ShotSoundEffect es vlido, reproducimos el efecto de sonido en la
posicin de la pistola. Recuerda que ShotSoundEffect y EmptySoundEffect los tenemos
como propiedades de la clase y la idea es que desde el editor se pueda cargar, para cada
una de estas propiedades, el efecto de sonido correspondiente.

Por ltimo, decrementamos la cantidad de municiones.


En caso de que la pistola se quede sin municiones, simplemente preguntamos si
EmptySoundEffect es vlido, y si lo es, reproducimos el efecto de sonido.
Listo !!, ya tenemos la implementacin completa de la escopeta que podr usar nuestro
personaje, pero an no tenemos nada visible para probar, ya que necesitamos antes,
implementar el mecanismo para que el personaje pueda recoger y equipar la escopeta.
Tmate unos minutos y seguimos con eso ;)
Implementando un sistema de inventario
Nuestro personaje tendr distintas formas de defenderse. Podr usar las manos y
defenderse a base de puetazos, como ya vimos en los dos tutoriales anteriores, pero
adems, podr equipar distintas armas y usarla contra sus enemigos.
En los juegos que tienen estas caractersticas, es clsico contar con un sistema de
inventario, donde el jugador puede agregar el arma al espacio del inventario
correspondiente a ese tipo de objeto y seleccionar del inventario el objeto que quiere
equipar para usar.
Para no extender el tutorial, solamente implementaremos la lgica para usar un arma, en
este caso una escopeta, pero al terminarlo vers lo fcil que resultar agregar otras
armas.
Primero, vamos a explicar un poco el principio que usaremos. Bsicamente un
inventario lo podemos ver como un cajn imaginario con distintos compartimentos.
Cada uno de estos compartimentos puede estar vaco o almacenar un elemento
especfico. En nuestro caso, sera un cajn con dos compartimentos. El primero puede
tener una escopeta, y en el caso que la tenga, la podemos seleccionar para defendernos
con ella, el segundo sigue el mismo principio solo que en vez de escopeta o armas
pesadas, estar destinado para pistolas.

Ejemplo grfico del inventario. En este caso el inventario estara lleno, pero si
tuviramos, por ejemplo, solo la escopeta, el segundo elemento del cajn estara vaco.

El elemento ideal que tenemos para implementar este tipo de cosas a nivel de
programacin son los arreglos. Un arreglo, vindolo abstractamente, es un cajn en la
memoria con distintos compartimentos. Podemos obtener el elemento que se encuentra

en un compartimento a partir del ndice (su posicin en el arreglo, siendo 0 la primera


posicin).
El nico detalle a tener en cuenta es que en un arreglo todos los elementos tienen que
ser del mismo tipo, pero usando la herencia y el polimorfismo (conceptos bsicos de la
programacin orientada a objetos) podemos definir que nuestro arreglo ser de
elementos de una clase base, digamos Weapon y podemos tener instancias de objetos
que heredan de Weapon, como sera Pistol para el caso de la pistola, por ejemplo, y
Shotgun para el caso de la escopeta.
Muy bien, ya basta de teora y vamos a la practica.
Abre el archivo HeroCharacter.h y agrega al inicio del fichero, debajo de los includes, lo
siguiente:
1
2

#define INVENTORY_GUN_INDEX

#define INVENTORY_PISTOL_INDEX

3
4

UENUM()

namespace EInventorySlot

enum Type

Gun,

10

Pistol,

11

None
};

12
13

Los dos #defines son simplemente constantes para usar a la hora de acceder a cada
posicin del arreglo. A continuacin creamos un enum que usaremos para identificar el
tipo seleccionado en el inventario. En nuestro caso tendremos tres variantes Pistola,
Escopeta o Ninguno. Este ltimo caso sera si el usuario no ha seleccionado ningn
elemento del inventario, ya sea porque no tiene o porque no ha querido, en este caso se
estara defendiendo a puetazos.
Muvete, hasta el final de la clase y agrega los siguientes atributos:

/** Evento cuando este AActor se superpone con otro AActor */


virtual void ReceiveActorBeginOverlap(class AActor* OtherActor)

2 OVERRIDE;
3

4 /* Inventario del player. En el primer index se tendr un arma tipo


5
6
7

escopeta y en el segundo un arma tipo pistola */


UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Inventory")
TArray<class AWeapon*> Inventory;

/* Compatimento del inventario actualmente seleccionado por el player


9 */

1 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Inventory")


0 TEnumAsByte<EInventorySlot::Type> InventorySelectedSlot;

El atributo Inventory es una arreglo de Weapons . En este guardaremos, en el ndice


correspondiente, la referencia de cada una de las armas recogidas. En este caso
usaremos el ndice 0 para las armas de tipo escopeta y el ndice 1 para las pistolas.
El atributo InventorySelectedSlot lo usaremos para saber en cada momento cual es el
elemento del inventario actualmente en uso.
Bien, pasa ahora a HeroCharacter.cpp y agrega al final del constructor las siguientes
lneas
1//Reserva el espacio para los items en el inventario. En este momento
cada uno de los espacios est en NULL

Inventory.AddZeroed(2);

3
4//Inicialmente no hay ningn elemento del inventario seleccionado
5InventorySelectedSlot = EInventorySlot::None;

Con la primera lnea lo que hacemos es reservar el espacio en memoria para nuestro
inventario. El mtodo AddZeroed de TArray nos permite agregar la cantidad de
elementos que indiquemos como parmetro al arreglo, pero en NULL, o sea, vacos, no
hay nada ah. Es como tener el cajn con todos sus compartimentos vacos.
Adems de esto, inicializamos la variable InventorySelectedSlot en None, o sea, no
tendremos nada equipado, en este caso la nica forma que tendramos de defendernos
son las manos.

Ahora vamos a implementar la lgica para poder recoger el arma del escenario. De
momento lo haremos muy simple, las armas estarn dispersas por el nivel y cuando le
pasemos por arriba, automticamente esta se agregar al inventario si no tenemos
ninguna otra arma de ese tipo. Para esto usaremos el mtodo
ReceiveActorBeginOverlap del personaje. Este mtodo es el que se dispara cuando se
detecta un Overlap entre este Actor y otro. Recuerda que para que se dispare este
mtodo tiene que estar en true el atributo Generate Overlap Events.
Muy bien, sabiendo esto, agrega la implementacin del mtodo
ReceiveActorBeginOverlap en HeroCharacter.cpp:
1 /** Evento cuando este AActor se superpone con otro AActor */
2 void AHeroCharacter::ReceiveActorBeginOverlap(class AActor*
OtherActor)

3
4

{
Super::ReceiveActorBeginOverlap(OtherActor);

5
6
7
8
9

//Chequea si el objeto con el que se est colisionando es un


Weapon
if(OtherActor->IsA(AWeapon::StaticClass()))
{
//Casteamos OtherActor a AWeapon dado que el parmetro de

1 ReceiveActorBeginOverlap es de tipo AActor


0

AWeapon *OtherActorAsWeapon = Cast<AWeapon>(OtherActor);

1
1
//Si el arma con la que estamos colisionando NO ha sido

1
equipada, o sea, que est en el escenario ...
2
1
3

if(OtherActorAsWeapon->bIsEquipped == false)
{

//Chequea si el arma con la que se est colisionando es


1
un
ASPAS12Weapon
4

1
5

if(OtherActor->IsA(ASPAS12Weapon::StaticClass()))
{

1
//Si el espacio para las armas de tipo escopeta del
6 inventario est libre...
1
7

if(Inventory[INVENTORY_GUN_INDEX] == nullptr)

1
8
1
9
2
0

{
//Colocamos en el primer index del arreglo
Inventory una referencia a este objeto
Inventory[INVENTORY_GUN_INDEX] =
OtherActorAsWeapon;

2
//Adjunta la pistola al Socket del Mesh del
1 personaje, donde guarda las armas de tipo escopeta.
OtherActorAsWeapon->AttachRootComponentTo(Mesh,
2
2 "HolsterSocket", EAttachLocation::SnapToTarget);

2
3
2
4
2
5
2
6
2
7

//Ejecuta la lgica que tenga el arma cuando es


tomada por el personaje
//En este caso simplemente se pone en false
bIsEquipped y se muestra un log en la pantalla
OtherActorAsWeapon->OnCollected();
}
else //... si ya tienes en el compartimento del
inventario para las escopetas, una escopeta ...
{

2
8

// ... mostramos un log en la pantalla.

//Otra variante puede ser, incrementar las


municiones
de
esa
arma
2

9
3
0
3
1
3
2

GEngine->AddOnScreenDebugMessage(-1, 15.0f,
FColor::Red, "Ya tienes una escopeta equipada !!");
}
}

//@TODO:
//Aqu puedes agregar el chequeo de otro tipo de arma,

3 como una pistola por ejemplo,


3

//y agregarlo el Inventory usando el index

3 INVENTORY_PISTOL_INDEX
4
3
5

3
6
3
7
3
8
3
9
4
0

}
}

4
1}
4
2
4
3
4
4
4
5

Ve con detenimiento por los comentarios, lnea a lnea, para que puedas entender en
cada paso lo que se hace. A modo de resumen, lo que hacemos es determinar si estamos
colisionando con un arma, si es as, miramos que tipo de arma es, para agregarla al
ndice indicado en el arreglo Inventory. Adems, la anclamos al HolsterSocket del
personaje.
Muy bien !!, vamos a probar esto. Compila y abre el editor. Desde el panel Mode
selecciona All Classes y agrega al escenario una SPAS12Weapon, recuerda colocarla
alineada al personaje para que este pueda colisionar con ella.
Ahora, desde el panel Details en la seccin Static Mesh selecciona el Mesh de la
SPAS12. En este mismo panel, busca la seccin Sounds y vers las dos propiedades
Shot Sound Effect y Empty Sound Effect. Carga en cada una el Sound Cue
correspondiente que creamos al inicio del tutorial, despus de importar los .wav.

Captura del editor con la SPAS12Weapon agregada al escenario despus de


seleccionarle el Mesh

Como notars el SphereComponent de la escopeta tiene su centro en la culata de la


escopeta. Este es otro problemita que se crea por tener el punto de pivote de este
StaticMesh en esa posicin, por eso hay que tener en cuenta el punto de pivote al
exportar el modelo desde el software de modelado 3D. De momento, para disimular
un poco el problema, podemos rotar la escopeta para que salga apuntando hacia arriba.
Muy bien !!, crea una copia de la escopeta y colcala en otra posicin, esto para
rectificar que tal como programamos, cuando el personaje tenga en el inventario una
escopeta, si le pasa por arriba a otra, no la podr recoger. Por supuesto, esta lgica la
podemos cambiar si queremos, por ejemplo, se pudiera comprobar que si tienes ya en el
inventario esa arma lo que se obtengan sean municiones. En fin, ya esto depende a lo
que quieras en tu juego, de momento lo haremos as para mantenerlo simple.
Listo!! guarda, corre el juego y camina hacia la escopeta. Cuando le pases por encima a
la primera, se detectar el evento Overlap y se agregar la pistola al Mesh del personaje
en el HolsterSocket (en la parte de atrs del cinturn). Ahora pasa por arriba de la
segunda escopeta, vers que esta se mantendr en el escenario y se mostrar en la
pantalla el log: Ya tienes una escopeta equipada !! , tal como queramos.

Captura del juego una vez que se recoge la escopeta del escenario y esta queda anclada
en el HolsterSocket del personaje.

Muy bien !!, ya tenemos el mecanismo necesario para recoger las armas, vamos ahora
con la segunda parte, cmo usarlas.
Preparando el AnimMontage para las animaciones cuando se est usando la
escopeta
Para el uso de la escopeta en general se necesitan varias animaciones. Necesitamos una
animacin para equipar la escopeta, otra para dispararla, otra para recargarla cuando se
le agoten las municiones y una ltima para guardarla. Vamos a usar para esto algunas de
las animaciones que vienen en el AnimStarterKit que bajamos del MarketPlace en el
tutorial pasado, recuerdas ?. En ese paquete de animaciones tenemos todas las que
necesitamos, no son perfectas, pero suficiente para el desarrollo del tutorial.
Pero, antes de poderlas usar tenemos un pequeito problema, y es que estas animaciones
vienen con su propio esqueleto, as que tenemos que apoyarnos de una opcin que nos

da Unreal Engine 4 que es genial. Y es la posibilidad de hacer un retarget de una


animacin de un esqueleto a otro. Para esto el esqueleto tiene que ser el mismo, como es
nuestro caso.
Busca en el Content Browser las siguientes animaciones: Equip_Rifle_Standing,
Idle_Rifle_Hip, Fire_Shotgun_Hip, Reload_Shotgun_Hip y ha cada uno dale clic
derecho Retarget Anim Assetes/Duplicate Anim Assets and Retarget. Esto te abrir una
ventana para seleccionar el nuevo esqueleto. Selecciona de aqu el esqueleto que usa
nuestro HeroCharacter. Repite esto para cada animacin y al terminar ya tendremos las
animaciones necesarias.

Ventana de seleccin del esqueleto para hacer el Retarget de la animacin

Ahora vamos a preparar un AnimationMontage con estas animaciones. En el Content


Browser, dentro de la carpeta donde tengas las animaciones del personaje, crea un
nuevo AnimMontage y nmbralo UsingShotgunAnimMontage. Dale como nombre de
Slot: UpperBody. Todas estas animaciones queremos que se fusionen con las
animaciones del State Machina para, por ejemplo, en lo que caminamos poder disparar.
Arrastra las siguientes animaciones en este mismo orden a la seccin Montage del
AnimMontage: Equip_Rifle_Standing, Idle_Rifle_Hip, Fire_Shotgun_Hip, de nuevo
Equip_Rifle_Standing (vamos a usar esta misma animacin para la accin de guardar el
arma, pero en realidad deberamos tener una animacin especfica para esta accin), por
ltimo Reload_Shorgun_Hip. Debes tener el Montage as:

Seccin Montage del UsingShotgunAnimMontage despus de agregar las animaciones

Ahora crea los siguientes Montage Sections: EquipShotgun para el inicio, sustituye el
Default por este. IdleShotgun para el inicio de la animacin Idle_Rifle_Hip.
FireShotgun para el inicio de la animacin Fire_Shotgun_Hip, HolsterShotgun para el
inicio de Equip_Rifle_Standing (recuerda que la usaremos tambin para guardar la
escopeta) y por ltimo ReloadShotgun al inicio de Reload_Shotgun_Hip. Te quedar de
la siguiente forma:

Seccin Montage del UsingShotgunAnimMontage despus de crear los Montage


Sections

Perfecto, vamos a preparar ahora las secciones para este AnimMontage. En el bloque
Sections da clic en el botn Clear. Ahora, como mismo hicimos en el tutorial de los
puetazos, crea las siguientes secciones:

Bloque Sections del UsingShotgunAnimMontage despus de crear configurar los


Montage Sections

La idea de esto es obtener el siguiente comportamiento. Para la primera seccin,


queremos que el personaje desenfunde la escopeta y se quede en el estado
Idle_Rifle_Hip en loop. Para la segunda seccin queremos que el personaje dispare la
escopeta y tambin se quede en Idle, para la cuarta seccin, es simplemente guardar la
escopeta, as que despus de guardar ya no se usara ms este Montage porque se
regresara a las animaciones del StateMachine. Por ltimo, para la ltima seccin,
queremos que el personaje recargue la escopeta y regresa a su estado idle en loop
tambin.
Perfecto !!, ya casi estamos listo para probar, pero nos queda un detalle. Si te fijas en la
animacin Equip_Rifle_Standing, esta animacin comienza y es ms o menos por la
mitad de la animacin cuando el personaje llega a tener la mano sobre la escopeta. O
sea que es exactamente en este momento donde tendramos que desanclar la escopeta
del HolsterSocket del personaje y anclarla al HandSocket. Bien, seguro que ya sabes
como resolver esto verdad ?? . . . exacto! Con los Branch Point del Montage.
Esto lo necesitamos tanto para la animacin de equipar el arma, como para enfundarla
as que crea en la posicin correcta, apoyndote con la pre-visualizacin, estos dos
Branch Points y nombralos EquipShotgun y HolsterShotgun. Te quedarn as:

BranchsPoints creados en el UsingShotgunAnimMontage en los puntos exactos donde


se enfunda y desenfunda el arma.

Muy bien, ya tenemos casi listo nuestro AnimMontage. Digo casi listo, porque an nos
queda incorporarle un detalle para la reproduccin de los efectos de sonido, pero de
momento vamos a probar sin ellos. Guarda estos cambios y cierra.
Antes de pasar para el cdigo tenemos que refactorizar dos cosillas en el AnimGraph del
HeroAnimBlueprint y tambin en el Blueprint del personaje, adems tenemos que
configurar los nuevos inputs que tendremos en nuestro juego. Primero, abre el Blueprint
del personaje y elimina el InputAction Punch donde ponemos en true/false la variable Is
Punching del personaje. Esta lgica la vamos a cambiar para que se ajuste a nuestro
nuevo mecanismo de defensa que ahora cuenta con un inventario con armas, adems de
los puos.
Por otro lado, abre el AnimGraph del HeroAnimBlueprint y cambia el nombre del Slot a
UpperBody (despus lo cambiaremos en el AnimMontage de los puetazos, no te
preocupes). Adems de esto, selecciona el nodo Layered blend per bone y en el panel
Details pon en true la opcin Mesh Space Rotation Blend. Esto es necesario para evitar
que al hacer el Blend entre las animaciones que usaremos para el uso de la escopeta y
las de locomocin, quede rotada la columna del personaje, esto nos permite asegurarnos
que la direccin a la que apuntar el cuerpo ser siempre la correcta. Puedes probar
despus poner esta propiedad en false para que veas cual es el efecto ms claramente.

Muy bien, ahora vamos a ajustar los nuevos controles de nuestro juego. Abre el Project
Settings/Input y configura los Bindings de tipo Action de la siguiente forma:

Nueva configuracin de los Action Mappings

Como notars tenemos cuatro Action Mappings nuevos. ReloadWeapon (R) lo usaremos
para recargar el arma. Attack (Clic izquierdo del Mouse) lo usaremos para atacar.
ActivateInventorySlot1 y ActivateInventorySlot2 (teclas 1 y 2 del teclado
respectivamente). Estas las usaremos para activar cada elemento del inventario, con la
tecla 1 activaramos el elemento en el primer compartimento, si tenemos alguno, y con
la tecla 2 el elemento del segundo compartimento.
Listo !! guarda y cierra el editor que nos regresamos al cdigo.
Abre el archivo HeroCharacter.h y agrega al final de la declaracin los siguientes
atributos y mtodos
1 /*
2 * Flag para saber si el player est atacando.
3 * Se hace true cuando se presiona el click derecho del mouse y false
cuando se suelta

*/

5 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Pawn")


6 bool IsAttacking;
7
8 /*
9 * Es llamado cuando se presiona la tecla 1.
1 * Enfunda/desenfunda el arma que est en el primer compartimento del
0

1 inventario (si hay alguna)


1
*/

1 void ActivateInventorySlot1();
2
1
3 /*
1 * Es llamado cuando se presiona la tecla 2.
4 * Enfunda/desenfunda el arma que est en el segundo compartimento
del inventario (si hay alguna)

1
5 */

1 void ActivateInventorySlot2();
6
1
/* AnimMontage para las animaciones del personaje cuando est usando
7
la escopeta */

1
UPROPERTY(EditDefaultsOnly, Category="Animations")
8
1
9

UAnimMontage* UsingShotgunAnimMontage;

2 //@TODO: Aqu puedes incluir los AnimMontage para el uso de otras


0 armas
2
1 public:
2
2
/**

2
3 * Se llama en el BranchPoint de la animacin en el momento de
equipar el arma

2
* Ancla el arma seleccionada a la mano del personaje
4
*/

2
5 UFUNCTION(BlueprintCallable, Category="Animations")
2 void OnEquipActiveWeapon();
6
2
/**
7
* Se llama en el BranchPoint de la animacin en el momento de

2 guardar el arma
8

2 * Ancla el arma al cinturn del personaje


9
*/

3 UFUNCTION(BlueprintCallable, Category="Animations")
0
3
1

void OnHolsterWeapon();

3 /** Inicia el ataque con el arma equipada */


2 void Attack();
3
3
/** Recarga el arma equipada */

3
4 void ReloadWeapon();
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4

IsAttacking: Lo usaremos como un flag para saber cuando el personaje est atacando.
Lo pondremos en true mientras est presionado el clic izquierdo del Mouse y en false
cuando se suelte.
ActivateInventorySlot1: Este mtodo lo llamaremos cuando el jugador presione la
tecla 1 y activar el primer elemento del inventario.
ActivateInventorySlot2: Este mtodo lo llamaremos cuando el jugador presione la
tecla 2 y activar el segundo elemento del inventario. En este tutorial no le daremos
ninguna implementacin, as que queda por tu cuenta agregar otro tipo de arma para el
segundo espacio en el inventario ;)
UsingShotgunAnimMontage: Es la instancia del AnimMontage que usar el personaje
para las animaciones del uso de la escopeta. Tiene que ser configurado desde el editor.
OnEquipActiveWeapon: Este mtodo ser llamado por el BranchPoint que creamos en
la animacin de desenfundar la escopeta y en este preciso momento se desanclar el
arma de HolsterSocket del personaje y se anclar en HandSocket.
OnHolsterWeapon: Es lo contrario del mtodo anterior. Ser llamado por el
BranchPoint que creamos en la animacin de guardar la escopeta y en ese preciso
momento se desanclar el arma del HandSocket del personaje y se anclar en el
HolsterSocket.
Attack: Este mtodo lo llamaremos cuando el jugador presione/suelte el clic izquierdo
del ratn y se encargar de iniciar el ataque con el arma equipada.
ReloadWeapon: Por ltimo, este mtodo lo usaremos para recargar el arma equipada.
Ser llamado cuando el jugador presione la tecla R.
Muy bien, pasa ahora a HeroCharacter.cpp. Inicializa en false el atributo IsAttacking al
final del constructor y agrega las siguientes lneas al final del mtodo
SetupPlayerInputComponent:
1InputComponent->BindAction("ActivateInventorySlot1", IE_Released,
this, &AHeroCharacter::ActivateInventorySlot1);

InputComponent->BindAction("ActivateInventorySlot2", IE_Released,

3this, &AHeroCharacter::ActivateInventorySlot2);
4
5InputComponent->BindAction("Attack", IE_Pressed, this,
&AHeroCharacter::Attack);

InputComponent->BindAction("Attack", IE_Released, this,

&AHeroCharacter::Attack);

7
InputComponent->BindAction("ReloadWeapon", IE_Released, this,
&AHeroCharacter::ReloadWeapon);

Agrega ahora al final de la clase la implementacin de los mtodos


ActivateInventorySlot1 y ActivateInventorySlot2
1 /*
2 * Es llamado cuando se presiona la tecla 1.
3 * Enfunda/desenfunda el arma que est en el primer compartimento del
inventario (si hay alguna)

*/

5 void AHeroCharacter::ActivateInventorySlot1()
6{
7
8
9

//Si el Slot actualmente seleccionado es distinto al de la


escopeta ...
if(InventorySelectedSlot != EInventorySlot::Gun)
{

1
0
1
1

//Si el slot para la escopeta est vaco ...


if(Inventory[INVENTORY_GUN_INDEX] == nullptr)
{

1
2

//Mostramos un log en la pantalla

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red,


"No
tienes
ninguna
escopeta para equipar");
1

3
1
4
1
5

}
else //... si el slot de la escopeta NO est vaco ...
{
//Mostramos un log en la pantalla
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red,

1
"Equipando la escopeta");
6
1
7
1
8

//Reproduce AnimMontage en la primera seccin, que es la


animacin de equipar la escopeta

if(UsingShotgunAnimMontage)

1
9

2
0

PlayAnimMontage(UsingShotgunAnimMontage);
}

2
1

//Actualiza el valor de InventorySelectedSlot para saber


2
en
otro
momento
que actualmente tenemos seleccionada la escopeta
2
InventorySelectedSlot = EInventorySlot::Gun;

2
3

2
4

else if(InventorySelectedSlot == EInventorySlot::Gun) //Si


tenemos
equipada la escopeta ...
2

2
//Lanza animacin para guardarla (Section HolsterShotgun del
6 UsingShotgunAnimMontage)
2
7
2
8

if(UsingShotgunAnimMontage)
{
PlayAnimMontage(UsingShotgunAnimMontage, 1.f,
"HolsterShotgun");

2
9

3
0}

3
1 void AHeroCharacter::ActivateInventorySlot2()
3{
2
//@TODO: Implementar la lgica para activar/desactivar el arma
3 del segundo compartimento del inventario

3
3
4
3
5
3

6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4

Como siempre, ve detenidamente lnea a lnea y apoyndote en los comentarios para


que entiendas a fondo lo que se hace. En general al presionar la tecla 1 comprobamos si
NO tenemos equipada la escopeta, si no la tenemos equipada rectificamos que en el
primer index del arreglo Inventory, que es el espacio destinado para las armas de tipo
escopeta, exista algn elemento. Si est vaco no podemos equipar nada por lo que de
momento mostramos un log en la pantalla , solo para que el usuario lo sepa. Si NO est
vaco, entonces reproducimos la animacin para equipar la escopeta y actualizamos el
valor de InventorySelectedSlot a Gun. Del resto se encargar el mtodo
OnEquipActiveWeapon en cuanto se dispare el BranchPoint correspondiente. Por
ltimo, en caso que ya tengamos una escopeta equipada, pues lo que hacemos es
reproducir la animacin de guardarla.
El mtodo ActivateInventorySlot2 te lo dejo para que lo implementes t ;) teniendo
como referencia el ActivateInventorySlot1 te ser muy fcil hacerlo, adems sera un
muy buen ejercicio.
Vamos ahora a implementar los mtodos OnEquipActiveWeapon y OnHolsterWeapon.
Agrega al final del HeroCharacter.cpp las siguientes implementaciones:
1 /**
2 * Se llama en el BranchPoint de la animacin en el momento de
equipar el arma

3 * Ancla el arma seleccionada a la mano del personaje


4 */
5 void AHeroCharacter::OnEquipActiveWeapon()
6

{
//Rectificamos que InventorySelectedSlot sea igual a Gun para

7 poder saber que index de Inventory usar


8

if(InventorySelectedSlot == EInventorySlot::Gun)

//Obtenemos la referencia al arma en el INVENTORY_GUN_INDEX


1
del
arreglo
0
AWeapon *Weapon = Inventory[INVENTORY_GUN_INDEX];

1
1
1
2
1
3

if(Weapon)
{
//Desancla el arma del HolsterSocket, para anclarla en la
mano

1
4

Weapon->DetachRootComponentFromParent(true);

1
5

//Ancla la pistola al Socket en la mano

1
Weapon->AttachRootComponentTo(Mesh, "HandSocket",
6 EAttachLocation::SnapToTarget);
}

1
7

1}
8
1
9 /**
2 * Se llama en el BranchPoint de la animacin en el momento de
0 guardar el arma
* Ancla el arma al cinturn del personaje

2
1 */

2 void AHeroCharacter::OnHolsterWeapon()
2
{

//Rectificamos que InventorySelectedSlot sea igual a Gun para


poder saber que index de Inventory usar

2
4
2
5
2
6

if(InventorySelectedSlot == EInventorySlot::Gun)
{
//Obtenemos la referencia al arma en el INVENTORY_GUN_INDEX
del arreglo
AWeapon *Weapon = Inventory[INVENTORY_GUN_INDEX];

2
7

if(Weapon)

2
8

{
//Desancla el arma del HandSocket, para anclarla en la

2 mano
9

Weapon->DetachRootComponentFromParent(true);

3
0
3
1
3
2

//Ancla la pistola al HolsterSocket


Weapon->AttachRootComponentTo(Mesh, "HolsterSocket",
EAttachLocation::SnapToTarget);

3
//Reinicia el valor de InventorySelectedSlot a None, para
3 saber que no tenemos ningn arma equipada
InventorySelectedSlot = EInventorySlot::None;

3
4

3
5
3
6
3
7
3
8
3
9
4
0

}
}

4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8

Estos dos mtodos son casi uno la inversa de otro. El primero es llamado una vez que el
usuario selecciona la tecla 1 para activar el arma que tiene en el primer compartimento
del inventario. En ese momento, inicia la animacin para desenfundar el arma, y cuando
la animacin est en el punto donde el personaje tiene la mano ya sobre la escopeta,
gracias al BranchPoint que creamos, se llama el mtodo OnEquipActiveWeapon. Este
mtodo obtiene la referencia del arma desde el inventario, la desancla del HolsterSocket
y la ancla al HandSocket del personaje, para que este la pueda tomar en la mano. Por
otro lado, el mtodo OnHolsterWeapon es lo contrario.
Muy bien, ya tenemos implementada la lgica para equipar/guardar el arma. Ahora
vamos a implementar la lgica para dispararla. Agrega al final del HeroCharacter.cpp la
implementacin del mtodo Attack
1 /** Inicia el ataque con el arma equipada */
2 void AHeroCharacter::Attack()
3{
4
5
6
7

//Si IsAttacking es false, se est presionando el clic izquierdo


del mouse ...
if(IsAttacking == false)
{
IsAttacking = true;

8
9
1
0

//Hacemos un switch por los posibles valores que puede tomar


el InventorySelectedSlot
//para saber que arma est equipada e iniciar la lgica de
correspondiente

1
1

switch (InventorySelectedSlot)
{

1
2
1
3

case EInventorySlot::Gun: //Si est equipada la escopeta


{
//Obtenemos la referencia de la escopeta

1
4

AWeapon *Weapon = Inventory[INVENTORY_GUN_INDEX];

1
5

//Si an tiene municiones ...


if(Weapon->Ammo > 0)

1
6

1
7 escopeta

//Reproducimos la animacin del disparo con la

1
8

if(UsingShotgunAnimMontage)
{

1
9 "FireShotgun");

PlayAnimMontage(UsingShotgunAnimMontage, 1.f,

2
0

}
}

2
1

//Llamamos al mtodo Fire del arma

2
2

Weapon->Fire();

2
3
2
4
2
5
2

break;
}
case EInventorySlot::Pistol:
{

//@TODO: Iniciar ataque con pistola

6
2
7

break;

2
8

}
case EInventorySlot::None:

2
9

{
//@TODO: Iniciar ataque con golpes

3
0
3
1

break;
}

3
2

default: break;
}

3
3

3
else //Esta atacando, detiene la accin de atacar (se solt el
4 clic izquierdo del mouse)
3
5

{
IsAttacking = false;

3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3

}
}

4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2

Este mtodo es llamado cuando en el juego presionamos/soltamos el clic izquierdo del


mouse. Al ser presionado, hacemos un switch para determinar que valor tiene la variable
InventorySelectedSlot, para saber que arma es la que tenemos equipada, y con la que
vamos a atacar. Si es EInventorySlot::Gun quiere decir que tenemos equipada la
escopeta. En este caso obtenemos la referencia a la escopeta desde el inventario. Si la
escopeta tiene municiones, reproducimos la animacin del disparo de la escopeta y por
ltimo llamamos al mtodo Fire del arma, que es el encargado de toda la lgica del
disparo, como ya vimos.
Casi terminamos, pero si recuerdas cuando implementamos el mtodo Fire de la
escopeta, en cada disparo se decrementa la cantidad de municiones de esta. Si las
municiones llegan a cero nuestro personaje no podr disparar ms. Para solucionar esto
agregamos el mtodo ReloadWeapon. Este mtodo lo podemos llamar al presionar la
tecla R y se encargar de comprobar cual es el arma equipada, reproducir la animacin
correspondiente y llamar al mtodo Reload del arma, que tiene la lgica correspondiente
para recargarla. En nuestro caso simplemente reiniciamos la cantidad de municiones.
Pues bien, agrega la implementacin del mtodo ReloadWeapon al final de
HeroCharacter.cpp
1 /** Recarga el arma equipada */
2 void AHeroCharacter::ReloadWeapon()

3{
4

//Si est activa la escopeta

if(InventorySelectedSlot == EInventorySlot::Gun)

{
//Obtenemos la referencia

AWeapon *Weapon = Inventory[INVENTORY_GUN_INDEX];

8
9

if(Weapon)

1
0

1
1

//Reproducimos la animacin de recargando el arma

1
2

if(UsingShotgunAnimMontage)

PlayAnimMontage(UsingShotgunAnimMontage, 1.f,
"ReloadShotgun");
1

1
4
//LLamamos al mtodo Reload del arma

1
5

Weapon->Reload();
}

1
6
1
7

return;
}

1
8
1
9

if(InventorySelectedSlot == EInventorySlot::Pistol)
{

2
//@TODO: Aqu puedes agregar la lgica para recargar la
0 pistola
2
1
2
2
2

}
}

3
2
4
2
5
2
6
2
7
2
8
2
9

Listo !! compila y abre el editor. Antes de darle Play, abre el Blueprint del personaje en
el Modo Defaults y busca la propiedad Using Shotgun Anim Montage y selecciona el
UsingShotgunAnimMontage que creamos hace un rato, compila y guarda los cambios.

Por ltimo, en el UsingShotgunAnimMontage creamos dos BranchPoints. Estos


BranchPoints los usaremos para llamar a los mtodos OnEquipActiveWeapon y
OnHolsterWeapon en el momento exacto, como marcamos estos mtodos como
BlueprintCallable los podemos llamar desde el Blueprint sin problemas. Abre el
Animation Blueprint del personaje y agrega lo siguiente:

Trozo del HeroAnimBlueprint donde se agrega la llamada a los mtodo


OnEquipActiveWeapon y OnHolsterWeapon a partir de los eventos generados por los
BranchPoints creados en el UsingShotgunAnimMontage

Ahora s !! listo para la accin !?? . . . compila, guarda y ejecuta el juego.

Camina hacia la escopeta y cuando la tengas equipada toca la tecla 1 para activarla.
Despus que la tengas lista, da clic con el mouse para que comiences a disparar. Como
configuramos la escopeta para que tenga un mximo de 4 balas, despus de dar el cuarto
disparo no podrs disparar ms, porque te quedaste sin municiones, pero esto no es
problema :) toca la tecla R para que recargues el arma.
Agrega algn objeto al nivel al que le puedas disparar, asegrate de configurarle su
Collision Traces Response en Block para los Trace de tipo Visibility. Equipa la escopeta
y disprale. Vers que en la pantalla se muestra el log con el nombre del objeto, adems

se dibuja un punto rojo en el punto del impacto, que fue exactamente lo que
implementamos. En prximos tutoriales haremos cosas ms interesantes ;).
Por ltimo, vuelve a tocar la tecla 1 para que guardes la escopeta.
Bueno, hasta ahora va genial todo, eh ?! . . . pero an tenemos un detallito pendiente por
agregar. Si revisas en los efectos de sonido que tenemos, an nos quedan por usar dos
efectos el shotgload.wav que es el efecto de sonido al recargar la escopeta y
shotgr1b.wav que es el efecto al preparar la escopeta para prximo disparo. Pues bien,
vamos a usar estos efectos en cada momento y para esto usaremos los Anim Notifiy.
Introduccin a los Anim Notifies en Unreal Engine 4
Los Animation Notifications o simplemente AnimNotifies nos brindan una forma de
definir eventos en puntos especficos de una animacin. Son comnmente usados para
agregar efectos de sonido en la animacin, por ejemplo, el efecto del pasos en el
momento exacto donde en la animacin queda el pie en el suelo. O para emitir un
sistema partculas.
Vamos a usarlos en este caso para agregar el efecto de sonido al preparar la escopeta y
al colocar las balas al recargarla.
Abre el UsingShotgunAnimMontage y muvete hasta la seccin Notifies. Usa el
timeline para pararte en el punto de la animacin donde el personaje coloca la bala en la
escopeta. Esta accin la hace cuatro veces, o sea, coloca cuatro balas, por lo que
tendremos que agregar cuatro Notifies. En la seccin Notifies da clic derecho justo en el
punto exacto y selecciona Add Notify fjate que se despliegan varias opciones.
Tenemos, PlayParticleEffect y PlaySound, estos dos son notifies pre-creados. Adems
podemos seleccionar New Notify para crear un Notify especfico.
Una vez creado un Notify podemos recibir este evento desde el Animation Blueprint del
personaje, como mismo hemos hecho con los Branch Point. En este caso no es necesario
irnos por esta va gracias al notify pre-construido PlaySound.
Entonces, en el punto exacto donde se colocan las balas da clic derecho/Add
Notify/PlaySound y en el panel de detalles de ese notify, en la propiedad Sound
selecciona del Content Browser el Sound Cue que creaste a partir del efecto
shotgload.wav.

Repite el proceso para los 4 momentos de la animacin donde el usuario agrega una
bala. Por ltimo, muvete en el timeline hasta el punto en la animacin del disparo
donde el usuario prepara la escopeta para el prximo disparo y agrega otro
PlaySoundNotify con el efecto shotgr1b.wav.
Listo !!, guarda y dale Play. Dispara la escopeta y podrs escuchar detrs de cada
disparo, justo en el momento exacto, sincronizado con la animacin, el efecto
shotgr1b.wav. Ahora toca la tecla R para recargar y podrs escuchar tambin el efecto
shotgload.wav justo en el momento exacto. . . sper verdad !! :)
Refactorizando el Animation Blueprint para los puetazos.
Antes de terminar, tenemos que refactorizar el Animation Blueprint del personaje para
poder dar puetazos cuando no se tenga equipada ningn arma. Primero, abre el
PunchingAnimMontage y cambia el nombre de slot a UpperBody. Ahora, abre el
Animation Blueprint del personaje y modifcalo para que te quede de la siguiente forma:

Animation Blueprint del personaje. El bloque marcado en rojo es lo que se cambi.

Anteriormente aqu obtenamos directamente el valor de la variable IsPunching del


personaje, esta variable se haca true cuando se detectaba el evento Press el input Punch
y false con el evento Release. Esto lo cambiamos para ajustarlo al nuevo mecanismo,
ahora tenemos que comprobar si la variable IsAttacking est en true y el
InventorySelectedSlot est en None, si estas dos condiciones se cumplen es que el
personaje no tiene equipada ningn arma y est atacando, as que no queda otra que los
puos ;)
Listo !! guarda, y dale play al juego. Sin recoger ningn arma, da clic y vers como el
personaje comienza a lanzar puetazos, puedes recoger el arma del escenario y dar clic
y seguir dando puetazos. Ahora toca la tecla 1 para equiparla, cuando des clic lo que
har ser disparar el arma. Toca de nuevo la tecla 1 para guardarla y vuelve a dar clic,
volver a lanzar puetazos. Genial, no !?
Pues esto es todo por hoy. En prximos tutoriales estaremos agregando enemigos que
nos dispararan al vernos, implementaremos el HUD del juego con el Unreal Motion
Graphics y muchas otras cosas. Mientras tanto, me encantara escuchar tus comentarios
y recuerda que puedes seguirme en Twitter (@nan2cc), para que ests al tanto de los
prximos tutoriales.

Implementando un AI Character con un arma en UE4


2015/01/31 por darielns88 Deja un comentario
Hola, soy Dariel de la Noval (@darielns), Lead Programmer en Spissa Software
Solutions. He estado siguiendo los tutoriales de @nan2cc y la aceptacin que han estado
teniendo y me he embullado a sumarme en esta serie de tutoriales sobre el desarrollo de
juegos con Unreal Engine 4, aqu voy con mi primer tuto, ya me dirs que te parece.
En este tutorial vamos a unir muchas de las cosas que ya hemos visto en tutoriales
anteriores para agregar un enemigo a nuestro juego. Este enemigo estar patrullando
una zona del nivel con un arma, al acercarnos, comenzar a dispararnos hasta matarnos.
De igual forma, ya con el arma que configuramos para nuestro personaje en el tutorial
pasado, podremos defendernos de estos ataques.
NOTA: Este tutorial ha sido desarrollado con Unreal Engine 4.4.3, si ests trabajando
con otra versin puede que encuentres algunas diferencias, ya que el Engine est en
constante actualizacin. De ser as, djame tus comentarios al final del post y
buscamos juntos la solucin.
Importando los recursos necesarios al proyecto
La mayor parte de este tutorial toca muchos temas de Inteligencia Artificial que ya
vimos a fondo en tutoriales anteriores, por este motivo en vez de desarrollar esta parte
de nuevo, las importaremos directamente al proyecto.

Vamos a comenzar importando los recursos necesarios para tener rpidamente un


personaje controlado por IA patrullando una zona del nivel y que detecte cuando nos
acercamos a esa zona, como mismo hicimos en los tutoriales de IA anteriores.
Descarga los recursos necesarios desde aqu, al descomprimir el .zip tendrs lo
siguiente:
Dentro de la carpeta M1Garand tendrs el FBX del modelo del arma que usar el
enemigo. Este modelo al igual que el del arma del Player tambin fue descargada desde
tf3dm.com
Dentro de la carpeta AIEnemy tendrs los siguientes recursos:

AIEnemyAnimBlueprint: Animation Blueprint del enemigo.


Inicialmente solo contiene la lgica para las animaciones de reposo y
caminando.

AIEnemyBehaviorTree: Behavior Tree (BT) encargado de la AI del


enemigo. Inicialmente solo contiene el procesamiento para patrullar
una zona y detectarnos si nos acercamos a esa zona.

AIEnemyBlackboard: BlackBoard asociado al BT del enemigo. Solo


contiene 3 elementos: TargetPointNumber, TargetPointPosition e
IsActorDetected. Los dos primeros son utilizados en el algoritmo de
patrullado y el tercero en el algoritmo de chequear cuando nos
acercamos.

AIEnemyCharacterBlueprint: Blueprint del enemigo.

AIEnemyController: Controlador del enemigo. Inicialmente solo


contiene la asignacin del BT.

AIEnemyTargetPoint: Target Point que se utilizara para definir los


puntos claves en la zona de patrullado del enemigo.

CheckNearbyEnemy: Task del BT encargado de chequear cuando el


player se acerca al enemigo.

IdleWalkBlendSpace1D: BlendSpace utilizado para hacer un blend


entre la animacin de Idle y Walk del enemigo.

UpdateNextTargetPointTask: Task del BT con la lgica para seleccionar


el siguiente punto clave en el recorrido de patrulla del enemigo.

Para importar los recursos que estn dentro de la carpeta AIEnemy, primero asegrate
de tener en tu proyecto el AnimStarterPack. Despus, abre la carpeta donde se encuentra
ubicado tu proyecto desde el explorador de ficheros del sistema operativo y copia dentro
de Content, la carpeta AIEnemy.

Para el caso del FBX del arma que usar el enemigo, este imprtalo desde el FBX
Import del Unreal como ya hemos hecho antes. Una vez que importes el arma, brela en
el StaticMesh Editor, y como mismo hicimos para el arma del Player en el tutorial
pasado, crale un Socket de nombre FireSocket en la punta del can.

Captura del StaticMesh Editor con el arma del enemigo cargada despus de la creacin
del FireSocket

Abre el editor y vers en el Content Browser los recursos importados. Puedes tomarte
unos minutos para que le des un vistazo a cada elemento.
Por ltimo, desde tutoriales anteriores estamos usando el AnimStarterPack que puedes
descargar del MarketPlace. Pues, el personaje que viene en este paquete es el que
usaremos como enemigo, pero como tendr un arma en su mano, necesitamos crearle un
socket como mismo hicimos para el Player en el tutorial anterior.
Abre el HeroTPP que viene en el AnimStarterPack y crale un socket en la mano,
puedes usar como preview el arma que importamos para poder posicionar correctamente
el socket, llmalo HandSocket.

Captura del Persona Editor despus de crear el HandSocket para el enemigo

Preparando la zona a patrullar


Prepara en el nivel la zona que quieres que patrulle el enemigo y encirrala en un objeto
de tipo NevMeshBoundVolume.
Agrega al nivel dos AIEnemyTargetPoints, estos los usaremos para definir el recorrido
del personaje. Recuerda que nuestro juego es un scroll-side y nos movemos bsicamente
en un solo eje, por lo que el enemigo tambin se tendr que mover por un solo eje, as
que asegrate de que los dos AIEnemyTargetPoints queden alineados y paralelos a la
posicin del PlayerStart.
A cada uno de estos AIEnemyTargetPoints hay que definirle el orden que representarn
en el recorrido que estar haciendo el enemigo. Selecciona el primero y en el panel de
Detalles, en la seccin Default, dale valor de 0 a la variable Position. Selecciona el otro
punto y dale valor de uno.

Captura del ViewPort de la escena con los dos TargetPoints agregados y la


configuracin correspondiente para la propiedad Position

Por ltimo, agrega al nivel dentro de esta zona, el AIEnemyCharacter que acabamos de
importar y que tendremos en la carpeta AIEnemy. Recuerda ponerlo siempre alineado al
Player Start.

Captura del ViewPort de la escena despus de agregar el AIEnemyCharacter dentro de


la zona que va a patrullar

Compila, lanza el juego y muvete hacia el enemigo. Vers cmo estar rondando de
punto a punto y en cada punto esperar 2 segundos. Cuando detecte que estamos cerca
de l se imprime en la pantalla, a modo de log, el mensaje: Detectando Enemigo
Cercano!!
Te recuerdo que si tienes algn problema con esta parte por la que hemos pasado
bastante rpido, dale un vistazo a este tutorial donde implementamos toda esta lgica de
IA paso a paso.
Preparando el arma que usar el enemigo
Como ves, con lo hecho hasta ahora, tenemos el enemigo patrullando una zona del nivel
pero por las animaciones que tiene puedes darte cuenta que le est faltando su arma.
Vamos a agregar un arma en las manos de este personaje siguiendo el mismo principio
que usamos en el tutorial pasado. En ese tutorial, colocbamos algunas armas en el
escenario para que el Player las recogiera, pero si recuerdas, nunca creamos un blueprint
de estas armas, implementamos toda su lgica desde C++ y despus la agregbamos al
nivel desde la seccin All Classes.
Eso est bien, pero en el mundo Unreal una muy buena prctica es crear un Blueprint a
partir de las clases que tengamos implementadas en C++. Esto nos permite, por
ejemplo, modificar varios parmetros de la clase a nivel visual, una sola vez. Por
ejemplo, imagnate que queramos tener en distintas zonas del nivel varias armas del
mismo tipo. Si creamos un blueprint a partir de la clase Weapon que implementamos en
C++, le definimos el Mesh y las propiedades que queramos una sola vez desde el
blueprint, y despus agregamos las instancias de este blueprint al nivel.
Vamos a crear un blueprint a partir de la clase Weapon que implementamos en C++. En
el tutorial pasado implementamos toda la lgica del arma que usa el personaje, la
SPAS12. Si quisiramos usar la misma lgica de esta arma para el arma del enemigo,
pudiramos crear el blueprint a partir de esta clase que ya hicimos, pero por ejemplo,
supongamos que en el arma de este enemigo la lgica del disparo sea distinta. En este
caso creamos la clase para que herede de Weapon que es la clase base de las armas, y
entonces implementamos en ella las funcionalidades especficas de esta arma.
Dentro de la carpeta Weapons crea un nuevo Blueprint que herede de la clase Weapon
que implementamos en el tutorial pasado y ponle como nombre
M1GarandWeaponBlueprint. brelo, y en la seccin Components, muvete hasta la
propiedad WeaponMesh y en el panel de detalle dentro de la seccin Static Mesh
selecciona el Mesh del rifle que importamos al inicio.

Captura del M1GarandWeaponBlueprint que acabamos de crear.

Compila, salva los cambios y cierra este Blueprint.


Equipando al enemigo con un arma
Para el Player, en el tutorial pasado, acoplbamos el arma al socket una vez que este la
recoga del escenario. Pero en este caso, desde el inicio del juego el enemigo tendr
equipada su arma. Para lograr esto le agregaremos un nuevo componente desde el
Blueprint, el Child Actor Component.
Abre el AIEnemyCharacterBlueprint y desde la seccin Components, despliega el
combo Add Component, y selecciona Child Actor.

El Chilld Actor nos permite agregar como componente de un Actor, otro Actor
cualquiera. En este caso lo usaremos para agregarle el arma.
En este punto me gustara comentarte otro componente parecido, el StaticMesh. Este
nos permite agregar un StaticMesh cualquiera como componente hijo del Actor. Un
ejemplo de su uso pudiera ser si este personaje tuviera un sombrero y el sombrero fuese
un elemento independiente del modelo original. En este caso podemos agregarlo como
StaticMesh al personaje, y despus anclarlo a un socket determinado, como mismo
haremos con el arma.
Entonces, al ChildActor que agregamos ponle como nombre WeaponComponent,
seleccinalo y muvete en el panel de detalles del componente hasta la propiedad Child
Actor Component y aqu seleccinale el blueprint del arma que preparamos para el
enemigo.

Solamente nos queda anclar el arma al socket en la mano del personaje y esto lo
haremos en el Construction Script. En el modo Graph selecciona la pestaa
Construction Script, en la que inicialmente solo tenemos el nodo Construction Script.

Ya vimos en tutoriales pasados que el Construction Script se ejecuta en la inicializacin


del objeto, y es el lugar que tenemos para implementar las funcionalidades en el
momento de la creacin del Actor.
Vamos a anclar el arma al socket de la mano, y para ello utilizaremos el nodo Attach To.
Este nodo permite adjuntar un elemento determinado a otro y recibe los siguientes
parmetros:
Target: Este es el elemento que se desea adjuntar. En este caso, el componente
WeaponComponent.
In Parent: A quien vamos a adjuntar dicho target. En este caso, al mesh del enemigo.
In Socket Name: Socket al cual se adjuntar el elemento Target. En este caso ser al
socket de la mano (HandSocket ).
Attach Type: Este ser el modo en que se adjuntara. En este caso, Snap To Target.
Agrega al blueprint el nodo Attach To y asigna en cada parmetro los elementos
correspondientes. Por ltimo, enlaza el nodo Construction Script al Attach To. Te
quedar de la siguiente forma:

Construction Script en el AIEnemyBlueprint para acoplar el arma en las manos de este


personaje

Salva los cambios y compila. Cambia al modo componentes y podrs observar como
ahora el rifle sale en las manos de este personaje.

Captura de la pre visualizacin del personaje enemigo despus de compilar el


Construction Script donde se acopla el arma al HandSocket

Al correr el juego notars que ya el enemigo tendr el arma equipada y se mover con
ella en todo momento.
Implementado la lgica en el enemigo para que cuando nos detecte nos comience a
disparar
Ya tenemos a nuestro enemigo patrullando con su arma una zona del nivel, pero a pesar
de que el Player se le acerca, no le dispara, as que vamos a implementar la lgica para
cuando nos detecte nos comience a disparar. Para esto crearemos un nuevo Task en el
BT de este personaje, este Task se ejecutar cuando el enemigo detecte que tiene al
Player cerca y bsicamente lo que har es rotarse hacia l y poner en true la variable que
usaremos desde el Animation Blueprint para comenzar la animacin del disparo.
Abre el AIEnemyAnimBlueprint y crea una nueva variable, dale de nombre IsShooting
y de tipo bool. Guardar y cierra este Blueprint.
Crea un nuevo Task para el BT del enemigo y ponle como nombre RotateAndShoot y en
l implementa el siguiente algoritmo.

RotateAndShoot Task, encargado de rotar el enemigo en la direccin del Player y pasar


a true la variable para iniciar la animacin de disparo

Este Task se ejecutar cuando se detecte el personaje, pero fjate que el enemigo puede
detectar al Player estando en su direccin o no, por lo que primero tenemos que
garantizar que este rote en la direccin del personaje antes que nos dispare. Esto lo
logramos con un poco de matemtica bsica, rotando el vector de Location del enemigo
y el vector de location del Player y a partir de ese vector resultante creamos un Rotator
que afecte solo el eje X con el nodo Rotation From XVector y con el Rotator resultante
actualizamos la rotacin del enemigo. Hecho esto solo nos resta pasar a true la variable
IsShooting para que comience la animacin de disparo.
Este Task tambin tiene otro detalle. Si recuerdas cuando vimos los tema de IA a fondo
comentamos que los Task puede tener 3 estados. Primero, que termina su ejecucin
satisfactoriamente, segundo, que termina su ejecucin NO satisfactoriamente y un tercer
estado que es mantener el Task en pendiente. Este es el caso en el que el Task sea una
accin que demorar su ejecucin, como es el caso. Recuerda que el task se ejecuta, el
personaje rota hacia nosotros y comienza a disparar. Para hacer esto, y evitar que
mientras el BT del personaje caiga en un ciclo sobre este Task mientras est disparando,
fjate que no llamamos al Finish Execute del Task.
Bien, entonces, como necesitamos que este Task se ejecute solamente si el personaje
detecta que tiene al Player cerca, crearemos un nuevo Decorator en el BT para controlar
esto. Arrastra del borde inferior del CheckNearbyEnemy y crea un nuevo Decorator de
tipo Blackboard. Selecciona el decorator y en la seccin Flow Control de panel de
Detalles, en el atributo Observer aborts selecciona Both. En este caso lo que queremos
es que inmediatamente que IsActorDetected est en false se pase a ejecutar la otra rama,
para que contine como vigilante.
Selecciona el Decorator y en la seccin Blackboard, en el atributo BlackBoard Key,
selecciona IsActorDetected para definirle que este es el key del blackboard que
queremos comprobar y en Key Query selecciona Is Set para definirle el tipo de
condicin que queremos comprobar sobre el IsActorDetected.
Por ltimo arrastra del selector que tiene este Decorator y conctalo al RotateAndShoot.

Captura del BT del enemigo despus de agregar el RotateAndShoot y el decorator para


controlar su ejecucin.

Listo !! Guarda, compila, lanza el juego y muvete cerca del enemigo. Cuando este te
detecta, se detiene de su tarea de patrullar, y en ese punto la variable IsShooting toma
valor de true. Lo que nos queda es preparar la lgica de la animaciones para cuando esta
variable est en true, se comience a reproducir la animacin del disparo.
Configurando animacin de disparo del enemigo
Como las acciones de este enemigo son bastante bsicas (solamente camina de un lado a
otro y cuando nos detecta, se detiene ah mismo y comienza a disparar desde el lugar) la
lgica de la animacin de disparar la podemos implementar como un nodo nuevo del
StateMachine de este personaje, a este estado se pasar una vez que la variable variable
IsShooting sea true y cuando sea falso se retornar a la animacin de Idle/Walk.
Abre el StateMachine desde el AIEnemyAnimBlueprint y agrega el nodo Shooting con
las transiciones correspondientes, fjate que dentro de Shooting lo que hacemos es
reproducir la animacin Fire_Shotgun_Ironsights. Te quedar de la siguiente forma.

Maquina de estado del enemigo despus de agregar el estado Shooting

Salva los cambios, compila, lanza el juego y camina hasta el enemigo. Vers que cuando
te le acercas comienza a ejecutar la animacin de disparar, pero una vez que te alejas,
comienza a caminar como si se estuviera deslizando y con la animacin de disparando.
Porque pasa esto?. Porque, a pesar de haber hecho la mquina de estado del enemigo
correctamente, este solo regresa al estado de Idle/Walk una vez que la variable
IsShooting est en false. En el Task RotateAndShoot ponemos esta variable en true una
vez que el personaje est de frente al Player, pero en ningn punto del BT la ponemos
en false.
Vamos a corregir este detalle y lo haremos en el Service CheckNearbyEnemy, en el
punto en donde ya no se detecta que el Player est cerca vamos hacer que la variable
isShooting vuelva a tomar su valor de false, para que el enemigo regrese de nuevo a su
estado de caminando.

Sealado se encuentra la modificacin al CheckNearbyEnemy para pasar la variable


isShooting a false

Compila, salva los cambios y corre el juego. Una vez que te acercas al enemigo este se
detiene y comienza a disparar y si nos alejamos, continua caminando con la animacin
correcta.

Muy bien !!, ya tenemos a este personaje listo, pero aunque aparentemente nos dispara,
por las animaciones que reproduce, en realidad en el momento del disparo no pasa
absolutamente nada. As que vamos ahora a implementar la lgica del disparo para
poder determinar si le da al Player y poderle aplicar un dao a este.
Implementado lgica del disparo en el arma del enemigo
En el tutorial anterior, implementamos en C++ la lgica del disparo del arma que usa el
Player. En este tutorial vamos a implementar la lgica del disparo del arma que usar el
enemigo desde el Blueprint que creamos para esa arma. En realidad el modo de disparo
es prcticamente idntico y pudiramos usar el ya implementado, pero lo vamos a hacer
aqu de nuevo y desde blueprint, a modo de demostracin.
En la clase Weapon, la clase base para todas las armas, tenemos el mtodo virtual Fire,
para poder implementarlo en cada arma segn el tipo de disparo. Como tenemos el arma
del enemigo en el blueprint M1GarandWeaponBlueprint, implementaremos aqu el
mtodo Fire de ella, pero antes tenemos que corregir algo que se nos escap en el
tutorial anterior.
En la declaracin del mtodo Fire de la clase Weapon, como atributos al macro
UFUNCTION le pasamos BlueprintImplementableEvent. Este atributo permite que el
mtodo pueda ser implementado en el blueprint, pero tenemos que agregarle adems el
atributo BlueprintCallable, para que tambin se pueda llamar el mtodo desde el
Blueprint.
Abre el archivo Weapon.h y modifica los atributos del macro UFUNCTION del mtodo
Fire, para que te quede de la siguiente forma:
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category =
"Weapon")

2virtual void Fire();

Con esto ahora podemos implementar el mtodo Fire en el Blueprint del arma del
enemigo, y adems llamarlo cuando se vaya a disparar el arma.
Abre el M1GarandWeaponBlueprint en el modo Graph y podrs agregar un nuevo
evento, el Event Fire, y una vez agregado el nodo que representa este evento, podemos
implementar toda la lgica que queramos. Vamos a implementar este evento de la
siguiente forma:

VisualScript del evento Fire del M1GarandWeaponBlueprint

La lgica que seguimos aqu es prcticamente la misma que usamos en el tutorial


pasado para el arma del Player. Primeramente lanzamos una lnea imaginaria desde la
posicin del FireSocket, x unidades hacia delante. Recuerda que estas unidades estn
definidas en la variable ShotDistance, puedes darle el valor que prefieras a esa variable
para definir el alcance del disparo.
Un detallito interesante a comentar, fjate que para el rayo tambin restamos 30
unidades en el eje z, esto es un parche por nuestro modo de juego scroll-side, las
animaciones que tenemos y la posicin en la que queda el rifle del enemigo cuando est
disparando, que no queda alineado a la posicin del Player, y debido a esto, si no
hacemos este ajuste en la posicin del rayo, este nunca colisionar con el personaje.
Otra posible solucin y en realidad muy aplicada en este modo de juego, es que los
personajes tengan una caja de colisin cuadrada algo ancha hacia los lados y estas
colisiones controlarlas contra esta caja de colisin.
Bien, por ltimo comprobamos si el rayo impact con el Player y si es as le aplicamos
un dao. Fjate que, aunque no lo hacemos aqu, para las armas puede resultar
interesante usar una variable para definir la cantidad de dao que esta ocasiona.
Por ltimo, a diferencia del Fire del arma que usa el Player, en este caso no tenemos en
cuenta las municiones. Un muy buen ejercicio que te puedes platear es implementar la
lgica para que el enemigo tenga que recargar el arma si se queda sin municiones.
Incluso, que pueda ir en bsqueda de municiones que estn en el escenario, recogerlas y
despus continuar con el ataque. En fin, lo puedes hacer todo lo complejo que quieras ;)
Muy bien, con esto ya tenemos el mtodo de Fire de esta arma, ahora necesitamos
llamar a este mtodo en el momento en el que el enemigo hace el disparo. En el tutorial
pasado implementamos un mtodo llamado Attack en el HeroCharacter, donde
comprobamos el arma que tiene equipada, e implementamos la lgica necesaria segn el
arma y finalmente llamamos al mtodo Fire del arma. En realidad en este caso no es
necesario un mtodo as porque el enemigo ni tan siquiera tiene un inventario, tiene una
sola arma y siempre la podr disparar, pero vamos a aprovechar este punto para ver una

cosilla nueva que tenemos en los blueprints. La posibilidad de crear funciones para
encerrar determinada lgica y despus poderla llamar simplemente como llamamos una
funcin cualquiera.
Abre el AIEnemyCharacterBlueprint y fjate que en el panel MyBlueprint, al lado del
botn para crear una nueva variable, tenemos un botn para crear una funcin. Vamos a
crear una nueva funcin de nombre Attack, en nuestro caso ser muy simple, obtenemos
la referencia del WeaponComponent y llamamos al mtodo Fire, pero por ejemplo, si tu
enemigo puede portar distintas armas la lgica de este proceso de atacar puede ser ms
compleja y por eso sera conveniente que la tengas en una funcin aparte, como mismo
haramos en C++.
Despus de creada la funcin Attack, entra en su modo de edicin e implementa lo
siguiente:

Funcin Attack creada en el blueprint del enemigo. Esta funcin se ejecutar cuando el
enemigo dispare su arma.

Listo !! ya tenemos el mtodo Fire del arma y el mtodo Attack del enemigo, solo nos
va quedando el evento que usaremos para llamar al mtodo Attack.
Si abres la animacin Fire_Shotgun_Ironsights en el Persona Editor y la analizas con
detenimiento, vers que el momento exacto del disparo es un poquito despus que inicia
la animacin. Pues bien, ser en ese preciso momento donde ejecutaremos el mtodo
Attack que acabamos de crear y para esto usaremos los Notifies.

Crea un Notify casi al inicio de la animacin Fire_Shotgun_Ironsights (donde se ve que


es justamente el inicio del disparo) y dale de nombre FireNotify. Con esto haremos que
el mtodo que tiene toda la lgica del disparo del arma se llame en el momento justo.

Captura del Fire_Shotgun_Ironsights, despus de crear el FireNotify

Ahora abre el Blueprint Animation del enemigo, agrega el nodo del Notify que
acabamos de crear y llama el mtodo Attack, para que dispare el arma que tiene
equipada cunado la animacin pase por ese punto.

Trozo del AIEnemyAmimBlueprint con el algoritmo a ejecutar cuando se lanza el


FireNotify

Compila, salva los cambios y corre el juego. Acrcate al enemigo y vers que ya en el
momento del disparo, se lanza el Trace para simular la trayectoria del proyectil, pero
como notars, el trace traspasa el Player. Esto pasa porque en la configuracin de
colisin del Mesh del Player, el Trace Response no lo tenemos configurado para que
bloquee el trace.
Abre el HeroBlueprint en el modo de componentes, ve al rbol de componentes y
selecciona el Mesh. Desplzate a la seccin Colisiones y busca el combo Collision
Presets y selecciona Custom. Luego marca como Block el parmetro Visibility de la
seccin Trace Responses.

Configuracin del Trace Responses en el Mesh del Player para que el rayo que se lanza
cuando el enemigo dispara su arma colisiones con este

Salva y lanza nuevamente el juego. Desplzate hacia el enemigo para que te dispare,
vers como ahora el rayo si impacta en el personaje.

Captura del juego en ejecucin en el momento en el que un disparo del enemigo


(derecha) colisiona con el Mesh del personaje protagnico (izquierda)

Implementado la lgica cuando el Player recibe dao


Ya tenemos implementado cuando el disparo del enemigo impacta con el Player y se le
aplica un Damage, ahora vamos a implementar la lgica necesaria para restar salud al
Player en cada disparo hasta que muera.
Primeramente necesitamos una variable en el Player que represente la salud de este.
Abre el archivo HeroCharacter.h y agrgale el siguiente atributo:
/** Salud del Player, disminuye cuando recibe dao, al llegar a cero
el personaje muere */

2UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Health)


3float Health;

Por defecto, la salud del Player ser 100. Abre el archivo HeroCharacter.cpp y agrgale
al final del constructor lo siguiente:

1 //La salud del personaje inicialmente ser 100


2 Health = 100;

Ahora, como vimos en el tutorial Cmo causar dao a un personaje, necesitamos


implementar el evento Any Damage que se dispara automticamente en el Actor
cuando recibe un Damage. Como toda la lgica de nuestro hroe, la hemos estado
implementado en C++, implementaremos este mtodo en C++ tambin. Aunque es
vlido aclarar, que si lo prefieres, lo puedes implementar en el Blueprint del Player.
De momento lo que haremos ser restar la salud del Player cada vez que reciba dao, y
cuando llegue a cero imprimir en la pantalla, a modo de log, que el Player ha muerto.
Abre el archivo HeroCharacter.h y agrega la declaracin del mtodo
ReceiveAnyDamage para implementarlo.
/**

* Es llamado automticamente por el Engine cuando se le aplica dao a


2este Actor

3* @param Damage. Dao que se le aplica al player


* @param DamageType. Clase con la informacin del dao aplicado.

* @param InstigatedBy. Controller que causa el dao

* @param DamageCauser. Actor que causa el dao

*/

virtual void ReceiveAnyDamage(float Damage, const class UDamageType*

8DamageType, class AController* InstigatedBy, class AActor*


DamageCauser) OVERRIDE;

Pasa ahora a HeroCharacter.cpp y vamos a implementar el mtodo


1 /**
2 * Es llamado automticamente por el Engine cuando se le aplica dao a
este Actor

3
4

* @param Damage. Dao que se le aplica al player


* @param DamageType. Clase con la informacin del dao aplicado.

5 * @param InstigatedBy. Controller que causa el dao


6 * @param DamageCauser. Actor que causa el dao
7 */
8 void AHeroCharacter::ReceiveAnyDamage(float Damage, const class
UDamageType* DamageType, class AController* InstigatedBy, class

9
1
0
1
1
1
AActor* DamageCauser)
2
1
3

{
//Si el player esta vivo ...
if (Health > 0)

1
4

1
5

//... decremento la vida con el dao aplicado


Health -= Damage;

1
6
1
7
1
8

//Mostramos un log en pantalla


GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red,
FString::Printf(TEXT("La salud del personaje es : %f"), Health));

1
9
2
0
2
1

//Si la salud del Player llega a cero, muere !!


if (Health == 0)
{
//Mostramos un log en la pantalla

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "El


2
player
ha
muerto");
2

2
3}
2
4
2
5
2
6

Compila y lanza el juego. Avanza hacia el enemigo para que te comience a disparar.
Vers que cada vez que te dispara, se imprimen en pantalla las vidas restantes del Player
y cuando llega a cero, se imprime el log que queremos.
Perfecto !!, ahora vamos a darle un poco de vida a estos dos momentos,
reproduciendo las animaciones en el Player cuando recibe los disparos y finalmente
cuando muere.
Implementando la animacin de Hit y Death del Player
Para la animacin de muerte del Player usaremos la animacin Death_1 que viene en el
AnimStarterPack. Primero tenemos que hacerle el retarget para usarla en el esqueleto de
nuestro personaje. Busca en el Content Browser, dentro del AnimStarterPack, la
animacin Death_1, dale clic derecho, Retarget Anim Assets/Duplicate Anim Assets and
Retarget. Selecciona de aqu el esqueleto que usa nuestro HeroCharacter.
Abre el HeroCharacter.h y como mismo tenemos un atributo para cargar desde el editor
el montage con las animaciones cuando el personaje tiene equipada el arma, vamos a
crear otro atributo de tipo AnimationAsset para cargarle desde el editor la animacin de
muerte.
1 /* Animacion del personaje al morir */
2 UPROPERTY(EditDefaultsOnly, Category = "Animations")
3 UAnimationAsset *AnimationDeath;

Hecho esto, pasa a HeroCharacter.cpp y en el punto donde imprimimos el mensaje de


muerte, vamos a cambiarlo para reproducir la animacin de muerte:
1 //Reproducimos la animacin de muerte
2 Mesh->PlayAnimation(AnimationDeath, false);

Compila y abre el editor. En el blueprint del personaje, asigna al atributo Animation


Death, la animacin Death_1 que preparamos.

Captura del HeroCharacterBlueprint donde le asignamos al atributo Animation Death el


Asset de animacin correspondiente

Si en este punto corres el juego vers un errorcillo. Se reproduce la animacin de muerte


cuando la salud llega a cero, pero si en ese momento sigues tocando las teclas de
moverte, el personaje sigue desplazndose por el escenario desde el piso, y esto
evidentemente est terrible !!. Para arreglarlo, usaremos el mtodo del Controller,
UnPossess. Recuerda un poco la teora que sigue el Framework de Unreal: El
PlayerController posee al Pawn del personaje y mediante este es que se manejan las
entradas del usuario. Con el mtodo UnPossess hacemos que el Controller desposea al
Pawn del personaje, y as quedan inutilizadas totalmente todas las entradas del jugador.
Adems, al hacer esto, el Service que tenemos en el enemigo que determina si estamos
cerca del Player ya no nos retorna verdadero y con esto, una vez que el enemigo mate al
Player, continuar patrullando la zona.
Regresa al HeroCharacter.cpp y despus que reproducimos la animacin de muerte
agrega las siguientes lneas:

1//Unposses del Controller


2Controller->UnPossess();
3
4//Destruye el component de collision bsica del player
5CapsuleComponent->DestroyComponent();

El DestroyComponent del Capsule Component lo llamamos para destruir la capsula de


colisin del Player, para si se da el caso en el que el enemigo nos mata dentro de su
zona de patrullaje, no colisione con esta capsula y puede pasar por arriba del cadver
sin problemas.

Captura del juego en ejecucin una vez que el enemigo nos mata, y nuestro personaje
queda muerto, tendido en el suelo.

Muy bien, solo nos va faltando un detallito, cada vez que el Player reciba un disparo,
sera genial que reprodujera alguna animacin no crees ? Pero, en este caso tenemos dos
detalles importante a tener en cuenta.
Primero, esta animacin de hit, tenemos que reproducirla mediante un Montage para
poder mezclarlas con la animaciones de caminando/reposo, para que el personaje pueda
caminar cuando reciba el disparo y estas dos animaciones se fusionen. Segundo,
tenemos dos casos, cuando recibe el disparo teniendo el arma equipada y cuando lo

recibe sin tener el arma equipada, por lo que tenemos que usar dos animaciones
distintas.
Para este tutorial usaremos la misma animacin, porque la verdad es que no tengo
ninguna otra a mano y el AnimStarterPack no tiene ninguna animacin para este caso :
( . . . de todas formas creo que a modo de demostracin es suficiente. En el
AnimStarterPack localiza la animacin Hit_React_1 y realiza todo el proceso de
retarget de animacin para usarla en el esqueleto de nuestro hroe.
Abre el UsingShotgunAnimMontage que preparamos en el tutorial anterior. Arrastra la
animacin que acabamos de hacerle el retarget para el final del montage, justo despus
del Reload. Crea una nueva seccin de nombre Hit justo al comienzo de la animacin de
Hit y en el bloque Sections, agrega una que reproduzca el Hit y despus caiga en el Idle
en loop ya que es justamente lo que queremos. El Player recibir el disparo, reaccionar
a este disparo con un pequeo gesto y continuar en su reposo con su arma en la mano.

Captura de la seccin Montage del UsingShotgunAnimMontage. Al final tenemos la


ltima seccin, de nombre Hit, con la animacin Hit_React_1

Captura de la seccin Sections Preview del UsingShotgunAnimMontage. La ltima


seccin es la que acabamos de crear, armada con el Hit y a continuacin el Idle en loop.

Ahora crea otro Montage para el caso en el que se reciba un disparo sin tener ningn
arma equipada. Crea un nuevo montage con el nombre HitAnimMontage, ponle como
nombre en el slot UpperBody, el mismo nombre de slot que hemos estado usando para
los montages, y agrgale la misma animacin Hit_React_1 o si tienes otra mano, para
no repetir esta misma , usa la tuya ;)

Captura del HitAnimMontage.


Ya tenemos los dos montages configurados, ahora solo nos falta usarlos. Abre el
HeroCharacter.h y agrega el atributo para desde el editor cargar el montage que
usaremos cuando reciba el disparo sin ningn arma equipada.
/* AnimMontage para la animacion del personaje cuando le impacta un
disparo del enemigo y este se encuentra sin el rifle equipado */

2UPROPERTY(EditDefaultsOnly, Category = "Animations")


3UAnimMontage* HitAnimMontage;

Ahora pasa al HeroCharacter.cpp y en el mtodo ReceiveAnyDamage, luego de restar la


salud del Player, agrega la lgica necesaria para reproducir estos montages segn sea el
caso. El mtodo completo te quedar as:
1 void AHeroCharacter::ReceiveAnyDamage(float Damage, const class
UDamageType* DamageType, class AController* InstigatedBy, class
2 AActor* DamageCauser)

3{
4

//Si el player esta vivo ...

if (Health > 0)

//... decremento la vida con el dao aplicado

Health -= Damage;

9
//Reproducimos la animacin de "hit" correspondiente segun

1
tenga o no equipada el arma
0

if (InventorySelectedSlot == EInventorySlot::Gun)

1
1

{
PlayAnimMontage(UsingShotgunAnimMontage, 1.f, "Hit");

1
2

1
3

else
{

1
4

PlayAnimMontage(HitAnimMontage, 1.f);

1
5

1
6

//Mostramos un log en pantalla


GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red,

1 FString::Printf(TEXT("La salud del personaje es : %f"), Health));


7
1
8
1
9
2
0
2
1

//Si la salud del Player llega a cero, muere !!


if (Health == 0)
{
//Mostramos un log en la pantalla
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "El

2 player ha muerto");
2
2
3
2
4

//Reproducimos la animacin de muerte


Mesh->PlayAnimation(AnimationDeath, false);

2
5
2
6
2
7
2
8
2
9
3
0

//Unposses del Controller

3
1

Controller->UnPossess();

3
2
3
3

//Destruye el component de collision bsica del player


CapsuleComponent->DestroyComponent();
}

3}
4
3
5
3
6
3
7
3
8
3
9

Compila, salva los cambios y por ultimo acrcate al enemigo. Haz las pruebas con y sin
el arma equipada y as veras al Player reproduciendo la animacin correcta para cada
estado
Ahora solo nos queda implementar algo muy parecido para el enemigo, un muy buen
ejercicio sera que lo intentaras hacer por tu cuenta. De cualquier forma, aqu te dejo
como sera.

Causando dao al enemigo


Si corres el juego en este punto y le disparan al enemigo, observars que pasa lo mismo
que nos pasaba con el disparo del enemigo al Player, la colisin con el rayo es ignorada
por el Mesh del enemigo, ya sabes como solucionar esto. Selecciona al enemigo desde
el nivel y en el panel de detalles muvete hasta la seccin de colisiones y ponle block al
parmetro visibility de trace response.
Abre el AIEnemyCharacterBlueprint y crea una nueva variable de nombre Health y
asgnale como valor inicial 100. Esta ser la salud del enemigo, como mismo hicimos
con el Player desde C++.

Variable Health del AIEnemyCharacterBlueprint para representar la salud de este


personaje

Abre el archivo SPAS12Weapon.cpp (el arma que usa el Player) y agrega el siguiente
cdigo en el mtodo Fire() justo despus que le pedimos el nombre al actor impactado,
bsicamente lo mismo que hicimos en el Fire del arma del enemigo.

//Aplica un dao de 20 al Actor al que le di el disparo.

UGameplayStatics::ApplyDamage(OutHit.GetActor(), 20, NULL, NULL,

2NULL);

El mtodo ApplyDamage que nos brinda el UGameplayStatics es el mismo que hemos


usado desde el blueprint. Recibe los mismos parmetros:
Actor al cual se le va a aplicar el dao.
Dao a aplicar.
Event Instigator se usa para definir el Controller que causa el dao.
Damage Causer se usa para definir el actor que causa el dao.
Damage Type Class nos permite definir una clase con propiedades especficas para
extender la informacin del dao aplicado.
Una vez hecho esto, nos falta implementar el evento Any Damage en el enemigo como
mismo hicimos para el Player. Salva todo y compila el cdigo.
Cuando el enemigo reciba un disparo del Player, le restaremos salud, si llega a cero se
reproduce la animacin de muerte (Death_2) de lo contrario reproduciremos otra
animacin y adems de esto usaremos una variable bool que nombraremos
TakingDamage, para controlar que mientras est recibiendo dao, no haga ninguna de
las otras tareas que tiene configuradas en el Behavior Tree.
Primero vamos a crear esta variable. Abre el AIEnemyAnimBlueprint, crea una nueva
variable de tipo bool y de nombre Taking Damage.
Ahora vamos a preparar las animaciones. La de muerte la reproduciremos directamente
con el Play Animation, as que no usaremos ningn montage, pero para el caso de la
animacin cuando recibe un disparo pero an no muerte si usaremos un montage.
Crear un nuevo montage, ponle como nombre HitAnimEnemyMontage y arrastra hacia
l las animaciones Hit_React_4 e Idle_Rifle_Hip_Break1 en este mismo orden y dale
como nombre de Slot HitSlot.
Ahora, fjate, antes de reproducir este Montage, pondremos la variable TakingDamage
en true, pero necesitamos que en cuanto termine esta animacin esta variable pase a
false y para eso usaremos un BranchPoint al final de la animacin. Crea uno y ponle de
nombre StopHit

HitAnimEnemyMontage con la creacin del BranchPoint casi al final de la animacin

Recuerda que para poder reproducir este montage en el enemigo, necesitamos tener el
slot configurado en el Animation Blueprint. Abre AIEnemyAnimBlueprint y agrgale un
nuevo Slot y ponle como nombre HitSlot para poder reproducir el Montage que
acabamos de crear. Por ltimo, conecta el StateMachine con este slot y luego este ltimo
al Final Animation Pose.

Captura del AIEnemyAnimBlueprint con el HitSlot para poder reproducir el Montage


HitAnimEnemyMontage, usado cuando el personaje recibe un disparo pero an no
muere

Bien, ya tenemos todos los recursos necesarios as que abre el


AIEnemyCharacterBlueprint y vamos a implementar el evento Any Damage que
bsicamente har lo siguiente: Primero le restamos la vida al enemigo. Luego, en el caso
de que la vida llegue a 0 reproducimos la animacin de Death_2 y eliminamos la
capsula de colisin del enemigo. En caso contrario ponemos la variable TakingDamage
en true y luego reproducimos el HitAnimEnemyMontage.

Any Damage del enemigo

Fjate que aqu, si es el caso en el que el personaje an no ha muerto, antes de


reproducir la animacin, ponemos en true la variable Taking Damage y mediante el
BranchPoint que creamos al final de esa animacin la pondremos en false nuevamente,
as que abre el AIEnemyAnimBlueprint implementa el evento
MontageBranchingPoint_StopHit que simplemente lo que har es poner esa variable en
false nuevamente.

Si corres el juego en este punto, notars que ya se reproduce la animacin, pero el


enemigo como que se desliza cuando est recibiendo el disparo. Esto sucede porque el
BT sigue el procedimiento normal y no sabe que el enemigo est recibiendo disparos.
Precisamente para esto fue que creamos esta especie de bandera Taking Damage que
ponemos en true cuando nos da el disparo y en false cuando terminamos de reproducir
la animacin. Vamos a usar esa variable ahora para mediante un Service en el BT para
evitar que si el enemigo est recibiendo dao pase a hacer cualquiera cosa.
Agrega un nuevo key en el blackboard de nombre TakingDamage y de tipo booleano.
Crea un nuevo Service de nombre TakingDamage y modifcalo para que te quede de la
siguiente forma:

Service TakingDamage para actualizar el valor del Key TakingDamage del BlackBoard
del enemigo con el valor de la variable TakingDamage que toma valor de true el tiempo
en el que el enemigo se est recuperando del disparo.

Con este Service listo, solo nos queda modificar el BT agregando al inicio del rbol este
Service y a continuacin el Decorator correspondiente para impedir que contine la
ejecucin del rbol en el tiempo en el que el enemigo est recuperndose de un
disparo.

BehaviorTree final del enemigo

Listo !! Guarda, compila, lanza el juego y divierte un poco intentado matar al enemigo
antes que l a ti ;)
Conclusin
Bueno, esto es todo por hoy, espero que te haya sido til este tutorial. Un muy buen
ejercicio que te puedo recomendar, es que intentes agregar ms enemigos al nivel, tal
vez en posiciones distintas, con distintas armas que causen ms o menos dao, armas
con lgicas de disparo distintas, en fin . . . todo lo que se te ocurra.
Otra cosa que te quera comentar. Como vez, la lgica de recibir dao y usar un arma,
entre el enemigo y el Player es prcticamente idntica. En proyectos reales, donde
generalmente tendremos varios personajes que compartan lgicas muy parecidas o
idnticas, no es nada recomendado implementar estas cosas de forma independiente por
cada personaje. Lo ideal es crear una clase base, que encapsule la lgica comn entre
los personajes. Como las animaciones si sern distintas entre los personajes, estas las
ponemos como propiedades de la clase, para que se pueda definir especficamente para
cada personaje sin afectar la lgica (como hacemos aqu en el HeroCharacter). En este
tutorial lo hemos hecho as sobre todo para demostrar las variantes C++ y Blueprint y
que las puedas comparar e ir familiarizndote con ellas, pero no olvides aplicar este
consejo en un proyecto real.
Ahora s, esto es todo por hoy :). En prximos tutoriales veremos como implementar el
HUD de nuestro juego, que es el mecanismo mediante el que el jugador tiene siempre
en pantalla la salud del personaje, el arma equipada, la cantidad de municiones etc.
Tambin nos servir para implementar una pequea barra de salud sobre este enemigo.
Adems, veremos dos clases muy importantes para el ncleo del juego, el GameState y
el GameMode. En fin, un montn de cosas interesantes vienen en prximos tutoriales,
as que mantente al tanto, y mientras, bueno ya sabes . . . nos encantara escuchar tus
comentarios.

Introduccin a los Delegates en Unreal


Engine 4
2015/03/08 por nan2cc Deja un comentario
En el desarrollo de videojuegos algo que necesitamos muy a menudo es notificar a los
distintos elementos del juego cuando ocurre algn evento, por ejemplo, cuando un
personaje muere, cuando las fuerzas enemigas comienzan a atacar nuestra base, cuando
alcanzamos un objetivo determinado del juego . . . en fin, en muchsimos casos. Es
precisamente en estas situaciones donde nos vienen a ser de gran ayuda los Delegates.
NOTA: Este tutorial ha sido desarrollado con Unreal Engine 4.6.1, si ests trabajando
con otra versin puede que encuentres algunas diferencias, ya que el Engine est en

constante actualizacin. De ser as, djame tus comentarios al final del post y
buscamos juntos la solucin.
Imaginemos un caso real. Supongamos que tenemos en nuestro juego al personaje
protagnico y a un grupo de distintos personajes secundarios, ya sean enemigos, aliados
o lo que sea, y queremos ejecutar algn comportamiento en cada uno de estos otros
personajes cuando el PlayerCharacter muere.
Una va de hacer esto es obtener la referencia del Player Character en el Event Tick de
cada uno de esos personajes, y preguntar por alguna variable que tengamos creada en el
Character que defina su estado en el juego.
Esta solucin funciona, es verdad . . . pero es terriblemente mala !!, porque cada uno de
los actores tienen que estar ejecutando un mtodo constantemente para poder saber el
estado del Player, con el consiguiente gasto de recurso que esto implica, sobre todo si
estamos hablando de un juego relativamente grande, donde varios actores estn
ejecutando esto en paralelo. Esto sera mucho ms desastroso si el proceso no fuera solo
preguntar por el valor de alguna variable, sino realizar algn calculo o algo por el estilo,
aqu el gasto de recursos sera an mayor.
Pues es precisamente esta una de las situaciones en donde los Delegates vienen a
salvarnos la vida. Un Delegate nos dan la posibilidad de bindiar a l uno o ms
mtodos de otras clases. De esta forma podemos en cualquier momento llamar este
Delegate y esto nos permitir ejecutar en cada una de esas instancias que bindiaron
mtodos a l, esos mtodos. O sea, que esto nos permite ejecutar un mtodo de otra
clase en el momento que queramos, sin ni tan siquiera tener acceso directo a ese
mtodo. Genial no !!??
Pues si volvemos a nuestro ejemplo, para solucionar este mismo problema podemos
crear un Delegate en la clase del personaje protagnico. Al iniciar el juego (o en
cualquier otro punto que queramos), le decimos a los otros Actores que registren un
mtodo de ellos que se va a llamar inmediatamente en el momento en el que este
Delegate sea lanzado. Hecho esto, en el momento en el que el Player muere, lanzamos
ese Delegate, y automticamente ser llamado en todas las instancias de las clases que
bindiaron mtodos a l, ese mtodo. Mtodo que tendra una implementacin
particular en cada una de las clases. Por ejemplo, en el enemigo se puede ejecutar
alguna animacin de alegra, y en el aliado, el mtodo puede ejecutar alguna animacin
de tristeza, o puede atacar directamente al enemigo . . . o cualquier otra cosa mucho ms
original y menos absurda :)
Mucho mejor esta solucin, verdad ?
Para entenderlo mejor y ver en la prctica como usarlo, vamos a preparar un pequeito
ejemplo. Veremos primero como trabajar con Delegates desde C++ para entenderlo todo
a bajo nivel, despus veremos la implementacin desde los Blueprints, y queda por tu
parte seleccionar la va que ms te guste cuando los vayas a implementar en tu juego ;)
Para este simple ejemplo he creado un proyecto nuevo en UE4 a partir de la plantilla
Top-Down en C++ y le he agregado 2 nuevas clases de Characters: RedCharacter y
GreenCharacter. Despus de esto he creado dos Blueprints a partir de estas clases,

RedCharacterBlueprint y GreenCharacterBlueprint. Para el Skeletal Mesh de ambos he


usado el mismo que usa MyCharacter al igual que con el Blueprint Animation.
RedCharacter y GreeCharacter podemos verlos como dos personajes cualesquiera que
puede tener nuestro juego.
Para diferenciarlos un poco vamos a crear dos Materiales muy simples, que sean de un
color completo. Los Materiales en Unreal son un tema bastante complejo y estn ms en
el campo de los diseadores, as que no nos detendremos en ellos ahora mismo. Para
crear un material da clic derecho en el Content Browser dentro de la carpeta donde lo
quieras crear, selecciona Material y dale un nombre, en este caso yo lo voy a llamar
RedMaterial. Dale doble clic para abrir el Material Editor que es el Editor de Materiales
que viene con el Unreal Editor.
Crea un nodo de tipo Constant 3Vector y en el panel de detalles de este nodo da clic
en la propiedad Constant y selecciona el color rojo en el Picker Color que se te
mostrar. Por ltimo conecta este nodo al Base Color del nodo RedMaterial. Con esto
hemos creado un material sper simple que al aplicarlo en el Mesh del RedCharacter
har que este se vea rojo en su totalidad, as lo podremos distinguir fcilmente.

Captura del RedMaterial en el Material Editor

Por ltimo, abre el RedCharacterBlueprint en el modo Components, selecciona el Mesh


y en la seccin Rendering vers la propiedad Materials que es un array. Agrega un
elemento dando clic en el smbolo de + y en el tem que se agrega, despliega el combo y
selecciona el RedMaterial que acabamos de crear. Vers como inmediatamente el
personaje toma color rojo.

Captura del RedCharacterBlueprint en el modo Components despus de settear el


RedMaterial como Material del Mesh

Ahora repite todo el proceso para configurar el GreenCharacterBlueprint, crea asgnale


a este un material de color verde.
Por ltimo, agrega el nivel cerca del PlayerStart una instancia del RedCharacter y una
instancia del GreenCharacter y elimina los obstculos que trae el nivel de esta plantilla
top-down. Con eso ya tendremos nuestra escena lista.

Captura del nivel preparado despus de eliminar los obstculos y agregar las instancias
del RedCharacterBlueprint y GreenCharacterBlueprint

Como comentamos, lo que queramos es implementar un mecanismo que nos permita


notificar a los otros dos personajes (Green y Red) cuando ocurre un evento determinado
en el juego, en este caso, cuando nuestro personaje muere, y para esto usaremos los
Delegates.
Implementando un Delegate desde C++ en Unreal Engine
En Unreal Engine 4 podemos declarar dos tipos de Delegates, Single-cast y Multi-cast.
Los Single-cast nos van a permitir notificar solo a un objeto determinado de nuestro
juego, por ejemplo, si quisiramos que solo el RedCharacter se entere de la muerte de
nuestro personaje. Por otra parte, los Multi-cast nos permiten notificar a todas las clases
que queramos. En la mayora de los casos usaremos Multi-cast, ya que estos tambin
podemos usarlo para notificar a solo una clase, as que vamos directamente a ver los
multi-cast, y comentamos en cada punto la diferencia a los Single-cast.
Como dijimos al inicio, el objetivo de los Delegates es permitirnos ejecutar un mtodo
determinado de otro objeto cuando ocurre algn evento del juego, incluso sin tener
acceso directo al mtodo de ese objeto, pero como sabes, los mtodos pueden tener
distintas estructuras. Un mtodo puede no retornar ningn parmetro ni recibir
parmetros. Puede tambin no retornar nada, pero recibir un parmetro o dos o los que
sean y as tenemos muchas variantes. Pues para declarar los Delegates en C++ el
compilador de Unreal nos brinda algunos macros especficos segn el tipo de mtodo
que vayamos a ejecutar al lanzar el delegate.
Function
Declaration macro
signature
void
DECLARE_MULTICAST_DELEGATE( DelegateName )
Function()
void Function( DECLARE_MULTICAST_DELEGATE_OneParam( DelegateName,
<Param1> ) Param1Type )
void Function(
DECLARE_MULTICAST_DELEGATE_TwoParams( DelegateName,
<Param1>,
Param1Type, Param2Type )
<Param2> )
void Function(
<Param1>,
DECLARE_MULTICAST_DELEGATE_<Num>Params( DelegateNam
<Param2>,
e, Param1Type, Param2Type, )
)
<RetVal>
DECLARE_MULTICAST_DELEGATE_RetVal( RetValType,
Function()
DelegateName )
<RetVal>
DECLARE_MULTICAST_DELEGATE_RetVal_OneParam( RetValTyp
Function( <Pa
e, DelegateName, Param1Type )
ram1> )
<RetVal>
DECLARE_MULTICAST_DELEGATE_RetVal_TwoParams( RetValTy
Function( <Pa pe, DelegateName, Param1Type, Param2Type )

ram1>,
<Param2> )
<RetVal>
Function( <Pa
DECLARE_MULTICAST_DELEGATE_RetVal_<Num>Params( RetV
ram1>,
alType, DelegateName, Param1Type, Param2Type, )
<Param2>,
)
Para nuestro ejemplo usaremos el caso ms simple que es ejecutar un mtodo sin valor
de retorno ni parmetros, pero al final la lgica es la misma para cada caso.
En el caso de la declaracin de los Delegates Single-cast, la lgica es la misma, solo que
se usa una variacin del macro sin la palabra MULTICAST, por ejemplo para el primer
caso sera DECLARE_DELEGATE
Lo primero que vamos a hacer es declarar este delegate. Abre el .h de la clase del
PlayerCharacter y antes de la declaracin de la clase agrega la declaracin del Delegate
de la siguiente forma:
1 DECLARE_MULTICAST_DELEGATE( FMulticastDelegateSample );
En este caso lo que acabamos de declarar es un multi-cast delegate al que se le pueden
bindiar mtodos que no retornan nada ni reciben parmetros. El prximo paso es
agregar una instancia de este delegate en la clase que lanzara el evento. En este caso es
nuestro personaje protagnico as que agrega como variable de clase del personaje, lo
siguiente:
1 FMulticastDelegateSample MulticastDelegate;
Ahora solo nos queda ejecutar este delegate en el momento que queramos. En este caso
vamos a crear un mtodo Die en el Player, este mtodo se llamar cuando el personaje
muera y en ese momento se lazar el delegate. Para adornar un poco el momento de la
muerte, reproduciremos una animacin dentro de este mtodo Die as que agrega
tambin una instancia de tipo UAnimationAsset para cargar el Asset de animacin desde
el Editor, como hemos hecho en tutoriales anteriores.
Agrega lo siguiente en el .h
1/** Asset de la animacion de muerte */
2UPROPERTY(EditDefaultsOnly, Category = Animations, meta =
(AllowPrivateAccess = "true"))
3UAnimationAsset *DeathAnimation;
4
5UFUNCTION(BlueprintCallable, Category=Default)
6void Die();
Ahora pasa al .cpp y agrega la implementacin del mtodo
1 void AUE4SampleCharacter::Die()
2 {
//Reproduce la animacin de muerte
3
if(DeathAnimation)

4
{
5
GetMesh()->PlayAnimation(DeathAnimation, false);
6
}
7
//Lanza el Delegate para notificar en todos los objetos que
8
9 bindiaron mtodo a este delegate que el PlayerCharacter acaba de
1 morir
MulticastDelegate.Broadcast();
0 }
11
Como puedes ver, es sper simple lanzar el delegate. Suficiente con llamar al mtodo
Broadcast(). Una vez que se llama este mtodo se ejecutar cada uno de los mtodos
que fueron bindiados a l en los objetos correspondientes.
Dos cosas a tener en cuenta con el Broadcast() es que lo podemos llamar incluso si al
delegate no se le ha bindiado ningn mtodo, como es en este preciso momento, y otra
cosa importante es que en caso que tengamos bindiado ms de un mtodo, el orden de
ejecucin de estos no es garantizado, as que tenlo en cuenta y no implementes ninguna
lgica que pueda depender de este orden.
Para el caso de los Single-cast, para llamarlos tenemos los mtodos Execute(),
ExecuteIfBound() y IsBound().
Con esto que hemos hecho hasta ahora ya tenemos creado y ejecutamos el delegate en el
momento que queremos, pero no hemos bindiado a l nada, por lo que al ejecutar el
Broadcast() simplemente no pasar nada. As que vamos a implementar el mtodo que
queremos llamar en el GreenCharacter y bindiarlo al delegate.
Bindiando mtodos al multi-cast delegate desde C++
Modifica la clase GreenCharacter para que te quede de la siguiente forma:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1

//---------------------------// GreenCharacter.h
//---------------------------#pragma once
#include "GameFramework/Character.h"
#include "GreenCharacter.generated.h"
UCLASS()
class UE4SAMPLE_API AGreenCharacter : public ACharacter
{
GENERATED_BODY()
/** Asset de la animacion de muerte */
UPROPERTY(EditDefaultsOnly, Category = Animations, meta =
(AllowPrivateAccess = "true"))
UAnimationAsset *DeathAnimation;
/** Mtodo que se llama en este clase, mediante el
MulticastDelegate del PlayerCharacter cuando este muere */

4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3

void OnPlayerCharacterDie();
void Die();
virtual void BeginPlay() override;
};
//---------------------------// GreenCharacter.cpp
//---------------------------#include "UE4Sample.h"
#include "GreenCharacter.h"
#include "UE4SampleCharacter.h"
#include "Engine.h" //Para poder usar el
GetWorldTimerManager().SetTimer
void AGreenCharacter::BeginPlay()
{
Super::BeginPlay();
//Obtiene la referencia del PlayerCharacter
AUE4SampleCharacter* PlayerCharacter =
Cast<AUE4SampleCharacter>(UGameplayStatics::GetPlayerCharacter(GetWor
ld(), 0));
//"Bindea" el mtodo OnPlayerCharacterDie de esta clase al
delegate que se lanza cuando el PlayerCharacter muere.
PlayerCharacter->MulticastDelegate.AddUObject(this,
&AGreenCharacter::OnPlayerCharacterDie);
}
/** Mtodo que se llama en este clase, mediante el MulticastDelegate
del PlayerCharacter cuando este muere */
void AGreenCharacter::OnPlayerCharacterDie()
{
//Delay de 1 segundo antes de llamar al mtodo Die de esta clase
GetWorldTimerManager().SetTimer(this, &AGreenCharacter::Die, 1.0,
false);
}
void AGreenCharacter::Die()
{
//Reproduce una animacin de muerte
if(DeathAnimation)
{
GetMesh()->PlayAnimation(DeathAnimation, false);
}
}

9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
El mtodo OnPlayerCharacterDie, que es el mtodo que vamos a bindiar al delegate del
PlayerCharacter, simplemente ejecuta un delay y al segundo llama al mtodo Die, que al

igual que el mtodo Die del PlayerCharacter, lo que hace es reproducir una animacin
de muerte. Cuando el PlayerCharacter muera y se notifique a este objeto, el
GreenCharacter esperar un segundo (para asimilar la noticia de que su compaero
muri :( . . . ) y tambin morir . . . Un poco trgica la historia ahora que lo pienso, as
que en tu juego usa los delegates para cosas ms alegres :)
OnPlayerCharaterDie ser el mtodo que se llamar automticamente cuando el
Delegate que creamos en el Character se dispare, pero para esto tenemos que bindiar el
mtodo al delegate y esto vamos a hacerlo en el BeginPlay.
Cuando necesitamos bindiar el mtodo de alguna clase a un delegate determinado, una
buena idea es hacerlo en el BeginPlay de esos actores, para ya no tener que
preocuparnos de eso en el transcurso del juego. Sobrescribe el BeginPlay de esta clase
para que te quede de la siguiente forma:
1
2
3
4
5
6
7
8
9
1
0

void AGreenCharacter::BeginPlay()
{
Super::BeginPlay();
//Obtiene la referencia del PlayerCharacter
AUE4SampleCharacter* PlayerCharacter =
Cast<AUE4SampleCharacter>(UGameplayStatics::GetPlayerCharacter(GetWor
ld(), 0));
//"Bindea" el mtodo OnPlayerCharacterDie de esta clase al
delegate que se lanza cuando el PlayerCharacter muere.
PlayerCharacter->MulticastDelegate.AddUObject(this,
&AGreenCharacter::OnPlayerCharacterDie);
}

En el BeginPlay de este character simplemente obtenemos la referencia al Character


accedemos a la instancia del delegate y mediante el mtodo AddUObject bindiamos el
mtodo que queremos ejecutar. El primer parmetro que recibe el AddUObject es la
instancia de la clase que contiene el mtodo que vamos a ejecutar, en este caso esta
misma clase, por eso el uso de this y el segundo es el mtodo que se va a ejecutar. Si
te fijas es muy parecido a lo que hacemos al bindiar los mtodos a las entrada del
usuario. En ese caso lo que hacemos es justamente esto mismo, bindiar un mtodo a un
delegate que se llama cuando el Engine detecta la entrada del usuario.
En este punto vale aclarar que por lo general vamos a bindiar a un delegate un mtodo
de un instancia UObject, pero el framework tambin nos brinda los mtodos Add(),
AddStatic(), AddRaw() y AddSP() para bindiar al delegate otro tipo de funciones, como
por ejemplo punteros a funciones globales. Para una referencia ms completa de cada
uno de los casos puedes darte una vuelta por: docs.unrealengine.com
Algo a tener en cuenta es que de la misma forma que agregamos mtodos al delegate,
podemos eliminarlos. Esto nos puede ser til si a partir de determinada condicin ya no
queremos que se notifique mas a un objeto de determinado evento. Para esto podemos
usar los mtodos del delegate: Remove() y RemoveAll()
Para bindiar mtodos en el caso de los Single-cast delegates tenemos los mismos
mtodos pero sustituyendo la palabra Add por Bind. Por ejemplo, para los multi-cast

tenemos AddUObject y para los single cast tenemos BindUObject. Para eliminar
tenemos el mtodo UnBind()
Listo !! . . . esto es todo lo que necesitamos. Guarda, compila y abre el editor.
Para facilitar la muerte de nuestro personaje (el evento que queremos notificar en todos
los otros personajes) vamos a forzarla a que suceda cuando se toque la barra
espaciadora, no es muy real pero nos permitir centrarnos en el asunto que de verdad
nos interesa en este tutorial. Abre el Project Settings y en la seccin Input agrega una
entrada de tipo Action, ponle de nombre KillPlayerCharacter y que se active con la
barra espaciadora
Ahora abre el Blueprint MyCharacter. Primero en el modo Default carga para la
propiedad DeathAnimation una animacin de muerte cualquiera que puedes obtener
haciendo un Retarget de cualquiera de las animaciones que vienen en el
AnimStarterPack.
Pasa al modo Graph y agrega lo siguiente para que cuando se presione la barra
espaciadora se llame al mtodo Die que implementamos en el PlayerCharacter.

Captura del Event Graph del PlayerCharacter. Ejecuta el mtodo Die cuando se detecta
el InputAction KillPlayerCharacter (Barra Espaciadora)

Hecho eso, compila, guarda y dale Play al juego. Presiona la barra espaciadora para
forzar la muerte de nuestro Character y vers que un segundo despus de la muerte del
personaje protagnico, el GreenCharacter tambin cae al suelo. Lo que nos demuestra
que se llam el mtodo correspondiente en esa instancia en el momento preciso. Genial
verdad !!??

Captura de dos momentos del juego. El primer cuadro, al iniciar el juego. El segundo
cuadro, al tocar la barra espaciadora el PlayerCharacter muere, lanza el Delegate de que
muri, es notificado el GreenCharacter mediante el mtodo OnPlayerCharacterDie,

inicia un Timer por 1 segundo y despus llama al mtodo Die, que hace que el
GreenCharacter muera tambin.

Bindiando ms de un mtodo de distintos objetos a un mismo Delegate


Como dijimos al inicio, la ventaja que tenemos con los delegate Multi-cast es que no
estamos limitados a bindiar un solo mtodo, sino que podemos bindiar todos los
mtodos que queramos de distintas clases. Por ejemplo, supongamos que tambin
queremos que cuando muera nuestro personaje se entere el RedCharacter y que
ejecute otra lgica.
Pues para esto no tenemos que hacer nada en espacial. Simplemente implementar el
mtodo que queramos en el RedCharacter y bindiarlo al delegate del PlayerCharacter en
el BeginPlay, como mismo hicimos con el GreenCharacter:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1

//---------------------------// RedCharacter.h
//---------------------------#pragma once
#include "GameFramework/Character.h"
#include "RedCharacter.generated.h"
UCLASS()
class UE4SAMPLE_API ARedCharacter : public ACharacter
{
GENERATED_BODY()
/** Material a usar en el Mesh de este Character cuando el
PlayerCharacter muere */
UPROPERTY(EditDefaultsOnly, Category = Materials, meta =
(AllowPrivateAccess = "true"))
UMaterial *PlayerCharacterDeadMaterial;
/** Mtodo que se llama mediante el MulticastDelegate del
PlayerCharacter cuando este muere */
void OnPlayerCharacterDie();
virtual void BeginPlay() override;
};
//---------------------------// RedCharacter.cpp
//---------------------------#include "UE4Sample.h"
#include "RedCharacter.h"
#include "UE4SampleCharacter.h"
void ARedCharacter::BeginPlay()
{
Super::BeginPlay();

2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6

//Obtiene la referencia del PlayerCharacter


AUE4SampleCharacter* PlayerCharacter =
Cast<AUE4SampleCharacter>(UGameplayStatics::GetPlayerCharacter(GetWor
ld(), 0));
//"Bindea" el mtodo OnPlayerCharacterDie de esta clase al
delegate que se lanza cuando el PlayerCharacter muere.
PlayerCharacter->MulticastDelegate.AddUObject(this,
&ARedCharacter::OnPlayerCharacterDie);
}
/** Mtodo que se llama mediante el MulticastDelegate del
PlayerCharacter cuando este muere */
void ARedCharacter::OnPlayerCharacterDie()
{
if(PlayerCharacterDeadMaterial)
{
//Cambia "al vuelo" el primer Material del Mesh de este
personaje
GetMesh()->SetMaterial(0, PlayerCharacterDeadMaterial);
}
}

4
7
4
8
4
9
5
0
5
1
5
2
Este mtodo lo que har ser cambiar el Material del Mesh del RedCharacter al que
carguemos desde el Editor en la propiedad PlayerCharacterDeadMaterial. Para el
ejemplo yo prepar un Material de color negro, de esta forma cuando el RedCharacter
sea notificado de la muerte del PlayerCharacter este se pondr negro al instante.
Guarda, compila y lanza el juego. Toca la barra espaciadora y vers como el
RedCharacter cambia a color negro al instante y el GreenCharacter, al pasar un segundo,
cae al suelto.

Captura del juego despus que muere el PlayerCharacter. Son notificados ambos
personajes. GreenCharacter muere al segundo y RedCharacter cambia su color a negro.

Muy bien, con este ejemplo hemos podido ver el enorme potencial de los delegates y la
forma de usarlos desde C++, pero como una de las potencialidades ms grande que tiene
el Unreal Engine es su mecanismo de VisualScripting mediante los blueprints, vamos a
ver como implementar este mismo tipo de mecanismos desde los blueprints.
Introduccin a los Event Dispatchers en Unreal Engine 4.
Como sabes, gracias a la magia que ha logrado el equipo de Epic con los Blueprints
para abstraernos de toda la complejidad que puede tener para muchos el asunto de C++,
todo esto lo podemos hacer sper fcil y rpido tambin desde Blueprints, aqu los
nombres varan un poco pero el concepto es el mismo.
En los blueprints podemos crear Event Dispatchers. Los Event Dispatchers sern
bsicamente los delegates, estos Event Dispatchers solamente los podemos ejecutar o
bindiar a ellos eventos de otros blueprints.
Para ver un ejemplo prctico, vamos a plantearnos algo simptico. Vamos a suponer que
nuestro personaje puede aumentar su fuerza a un nivel extremo y en ese caso se vuelve
negro, en el punto en el que nuestro personaje llega a este nivel, el RedCharacter que
sera su enemigo, se hecha a correr :).
Agrega otra Action al Project Settings/Input y llmalo Activate Super Power (o como
prefieras).
En el Event Graph del Character fjate que en el panel My Blueprint, desde el que
podemos agregar variables y funciones tambin tenemos la opcin para crear un Event
Dispatcher. Da clic aqu para crear uno y llmalo SuperPowerActivated.

Una vez creado, desde el Panel Detalles, en la seccin Inputs, podemos agregar
parmetros de entrada segn el mtodo que queramos ejecutar al llamar a este Event
Dispatcher, en nuestro caso no necesitamos ningn parmetro.
Ahora, modifica el Event Graph de la siguiente forma:

Esta es la lgica que se ejecutar cuando aumentemos de poder. A modo de


demostracin simplemente cambiamos nuestro color a negro.
Es en este preciso momento es cuando queremos notificar que aumentamos nuestro
poder, para esto arrastra desde el panel My Blueprint hasta el Event Graph, el Event
Dispatcher que creamos anteriormente. Al soltarlo te mostrar un men contextual con
las distintas opciones relacionadas con ese Event Dispatchers, selecciona de ah la
opcin Call.

Captura del EventGraph del MyCharacter despus de agregar el llamado del Event
Dispatcher una vez que el personaje incrementa su poder (cuando se detecta la entrada
de nombre ActivateSuperPower)

Listo, este es el sinnimo del Broadcast de C++. Con esto todos los mtodos que se
hayan bindiado a este Event Dispatchers se llamarn. Pero, como mismo vimos en C++,
si no bindiamos ningn evento a este Event Dispatcher no pasar nada, as que vamos a
ello.
Abre el RedCharacterBlueprint crea un Custom Event de nombre
OnPlayerCharacterIncreasePower e implementa en l el siguiente algoritmo.

A partir del Actor Location obtenemos un vector 1000 unidades detrs del personaje y el
aplicamos un AI Move To que har que este personaje salga corriendo hacia ese punto.

Listo ya tenemos el evento que queremos ejecutar cuando el PlayerCharacter aumente


su poder, ahora solo nos queda bindiarlo al Event Dispatcher del PlayerCharacter.
Como mismo hicimos en C++, vamos a implementar en el Begin Play el binding.
Necesitamos acceder al PlayerCharacter que es donde tenemos el Event Dispatcher, una
vez que tengamos el PlayerCharacter casteado a MyCharacter podemos seleccionar
Bind Event To . . . que nos permitir bindiar un evento a cualquiera de los Event
Dispatchers que existan en el PlayerCharacter. Fjate que podemos Bindiar un evento al
SuperPowerActivated que creamos, pero tambin podemos bindiar evento a muchos
otros momentos importantes, como el OnDestroyed, el OnTakeAnyDamage y
muchsimos otros eventos que nos brinda el Engine ya por defecto, as que ya sabes, si
en algn momento necesitas lanzar un evento cuando un Actor es destruido, por
ejemplo, puedes bindiar tu evento al OnDestroyed. Esto es algo que se usa mucho para
incrementar puntos, o hacer respawn de otros personajes, o si es el OnDestroyed del
PlayerCharacter, para dar el Game Over.
Retomando nuestro ejemplo, el EventGraph del RedCharacterBlueprint nos quedara
as:

Captura del EventGraph del RedCharacterBlueprint despus de implementar el Event


Begin Play, donde se obtiene la referencia al MyCharacter y se bindea el evento
OnPlayerCharacterIncreasePower al Event Dispatchers que se llama cuando el
PlayerCharacter aumenta de poder.

Listo !! . . . guarda los cambios y dale Play al juego. Toca la tecla para activar el super
poder, veras como nuestro personaje se vuelve negro, y el RedCharacter sale corriendo
como todo un cobarde :)

Conclusin
Este tutorial ha sido un poco ms corto que los de costumbre pero espero que haya
servido para darte un acercamiento a como trabajar con Delegates en Unreal Engine 4 y
que puedas explotar a partir de ahora esta fenomenal va que tenemos de notificar a los
distintos Actors de nuestro juego cuando un evento determinado ocurre.
Para profundizar en los Delegates desde C++ puedes darte una vuelta por la
documentacin oficial

. . . Y esto es todo por hoy. Seguiremos viendo nuevas cosas de Unreal Engine 4 en
prximos tutoriales as que no te vayas muy lejos. Tambin puedes seguirme en Twitter
(@nan2cc) y as te dejo saber cuando tengamos un nuevo tutorial. Mientras, me
encantara escuchar tus comentarios o temticas que quisieras que tocara en prximos
tutoriales. Hasta la prxima, bye ;)

Anda mungkin juga menyukai