Archivo de la etiqueta: Unreal Engine

UE4 – Consejo del día 1: Efecto de FadeIn/FadeOut en la cámara

Sabías que ….

Mediante la función StartCameraFade del PlayerCameraManager puedes crear efectos “FadeOut” o “FadeIn” en la cámara de forma muy fácil !

Ejemplo: Vamos a crear una función en nuestro PlayerController que al llamarla comience un fundido a negro de 3 segundos y al terminar el fundido se reinicie el nivel.

void AMyPlayerController::StartFadeOutAndRestartLevel()
{
	// Nos aseguramos que el PlayerCameraManager sea válido
	if (PlayerCameraManager)
	{
		// Inicia el fundido a negro (demorando 3 segundos desde que inicia hasta que se vuelve todo negro)
		const float Duration = 3.0f;
		PlayerCameraManager->StartCameraFade(0.f, 1.f, Duration, FLinearColor::Black, false, true);

		// Despues de los 3 segundos, justo al terminar el fade out, reiniciamos el nivel
		FTimerHandle TimerHandle;
		GetWorldTimerManager().SetTimer(TimerHandle, this, &APlayerController::RestartLevel, Duration, false);
	}
}

Lo mejor que tiene StartCameraFade es que es super configurable gracias a los parámetros que recibe:

FromAlpha: Valor de transparencia al comenzar el fade. 0 = Totalmente transparente, 1 = totalmente opaco.
ToAlpha: Valor de transparencia al terminar el fade. 0 = Totalmente transparente, 1 = totalmente opaco.
Duration: Cuantos segundos tomara el efecto
Color: Color del fade. Generalmente es negro, pero podemos hacerlo de cualquier color 😉
bShouldFadeAudio: True para afectar el volumen del audio junto con el efecto de fade.
bHoldWhenFinished. True para mantener el valor final del efecto. Se puede eliminar llamando a la función StopCameraFade

Este efecto de fundido a negro es muy usado en distintos lugares, un ejemplo clásico de su uso es al morir nuestro personaje, antes de reiniciar el nivel o dar las opciones para reiniciar, se puede fundir a negro para suavizar la transición. Ten en cuenta que al hacer el FadeOut NO se va a ocultar el HUD, por lo que deberás encargarte de ocultarlo antes.

😉

NOTA: Este post ha sido desarrollado usando el Unreal Engine 4.12.5, si estás trabajando con otra versión puede que encuentres algunas diferencias, ya que el Engine está en constante actualización. De ser así, déjame tus comentarios al final del post y buscamos juntos la solución.

English version: UE4 – Tip of the Day 1: Camera FadeIn/FadeOut

Desarrollando un Third Person Multiplayer Shooter en U4 – Parte 1

En este tutorial vamos a preparar la base de nuestro juego. Un personaje con su pistola en tercera persona. Podrá apuntar y disparar proyectiles en la dirección a la que apunta. Esto nos va a permitir, además de preparar la base de nuestro juego, ver varias cosas que nos ofrece el Engine y que no hemos visto en tutoriales anteriores, como los AimOffset, para implementar el movimiento de un personaje al apuntar. El ProjectileMovementComponent, que nos permite afectar en el Tick de un actor su posición a partir de una velocidad y gravedad, simulando el desplazamiento de un proyectil. Y justamente basados en este componente veremos como implementar un sistema de disparo con proyectiles. Así que sin más, manos a la obra !!

Requisitos previos: Para no extender innecesariamente cada tutorial, las cosas que ya hemos visto en anteriores entregas no las volvemos a abordar en detalles. Si recién comienzas tu aventura en el desarrollo de videojuegos con Unreal Engine 4, antes de continuar con este tutorial te recomiendo que le des un vistazo a los anteriores.

NOTA: Este tutorial ha sido desarrollado con Unreal Engine 4.8, si estás trabajando con otra versión puede que encuentres algunas diferencias ya que el Engine está en constante actualización. De ser así, déjame tus comentarios al final del post y buscamos juntos la solución.

Preparando los recursos para el proyecto.

Antes de comenzar a implementar cualquier cosa necesitamos los recursos de nuestro juego (modelos y animaciones) y si hay un lugar bueno para encontrar recursos para nuestras pruebas, estudios y tutoriales, ese es el Marketplace :).

Vamos a necesitar dos paquetes que hay en el Marketplace, que sí, son de pago :( pero con el precio que tienen para lo que nos brindan, son prácticamente un regalo. Me refiero al Pistol Anim Set Pro y el Military Weapon Silver

Captura de pantalla del Marketplace de los paquetes Pistol Anim Set Pro y Military Weapon Silver

Captura de pantalla del Marketplace de los paquetes Pistol Anim Set Pro y Military Weapon Silver

Con estos recursos a la mano ya podemos comenzar. Vamos iniciar nuestro proyecto a partir de la plantilla Third Person en C++. Los amantes a los blueprints se sentirán un poco mal, pero la realidad es que muchas de las funcionalidades orientadas al multiplayer en Unreal aún no están expuestas a Blueprints, por eso lo más probable es que si tu objetivo es desarrollar un juego multiplayer y quieras usar características avanzadas, vas a necesitar C++. Pero no te preocupes, que veremos también las opciones que tenemos desde blueprint, que la realidad es que para cosas simples sigue siendo una opción.

Configurando las animaciones básicas para el personaje.

Después de crear el proyecto a partir de la plantilla “Third Person en C++“ y agregar los recursos del Pistol Anim Set Pro y Military Weapon Silver Abre el Blueprint del Character y vamos a cambiarle el esqueleto para que use el Epic_Skeleton_Template_Skeleton que viene con el PistolAnimsetPro. En realidad es el mismo esqueleto que viene con Unreal pero todos los assets de animaciones del PistolAnimsetPro están hechos para esta copia del esqueleto. Haciendo esto nos evitamos el retarget de cada una de las animaciones que queramos usar. También con esto ya adelantamos la creación del socket en la mano del personaje para anclar el arma, este esqueleto que viene en el PistolAnimsetPro ya lo tiene creado.

Además de esto agrega los siguientes atributos a la clase del Character:

/** true cuando el personaje está apuntando su arma */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Character)
bool bIsAiming;

/** Animación de disparo con la pistola */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Animation")
UAnimMontage *ShotPistolAnimation;

En el constructor inicializa bIsAiming en true; ya que temporalmente, desde el inicio del juego el personaje estará apuntando y bUseControllerRotationYaw también ponlo en true;

Ahora vuelve al Editor y crea un BlendSpace1D con las animaciones Pistol_Idle, Pistol_WalkFwdLoop y Pistol_RunFwdLoop (la versión InPlace). Después ve al AnimationBlueprint del personaje y modifica el nodo Idle/Run en el StateMachine para que use este BlendSpace que acabas de crear. Si tienes duda de como hacer esto dale un vistazo a los primeros tutoriales donde se explica el proceso detalladamente.

Captura del BlendSpace en modo de edición. Los assets Pistol_WalkFwdLoop y Pistol_RunFwdLoop puedes colocarlos en el valor que prefieras según el MaxWalkSpeed de tu personaje al caminar y correr.

Captura del BlendSpace en modo de edición. Los assets Pistol_WalkFwdLoop y Pistol_RunFwdLoop puedes colocarlos en el valor que prefieras según el MaxWalkSpeed de tu personaje al caminar y correr.

En este punto tenemos la animación de reposo y caminando mientras está apuntando, pero tenemos un pequeño detalle que usaremos como pretexto para ver un Asset de animación que nos brinda Unreal y que no hemos visto en tutoriales anteriores. Hablo del AnimOffset.

Introducción al AimOffset en Unreal Engine 4

Si te detienes un segundo por algún Third Person Shooter que tengas a mano, como el Max Payne 3 por ejemplo, y analizas su comportamiento, verás que el personaje tiene dos estados (centrándonos solo en lo que se refiere a apuntar/usar su arma). Puedes estar apuntando el arma, listo para disparar (generalmente con el clic secundario se pasa a este estado) y con su arma abajo, que la tiene equipada pero no está apuntando. En el primer estado verás que por lo general el personaje rota su Yaw en dirección del Controller pero si apuntas hacia arriba o hacia abajo lo que hace es rotar el torso. Pues bien, es precisamente este segundo movimiento lo que podemos implementar gracias a los AimOffset.

El AnimOffset es un asset de animación que almacena una serie de poses que son “blendeados“ a partir de los parámetros de entrada, que por lo general son la rotación en los ejes Yaw y Pitch. De esta forma hacemos que nuestro character pueda apuntar su arma sin tener que rotar todo el cuerpo, ya sea horizontalmente o verticalmente.

Imagen tomada de https://docs.unrealengine.com/latest/INT/Engine/Animation/AnimHowTo/AimOffset/index.html donde se ve al personaje apuntando su arma en distintas direcciones sin rotar todo el cuerpo, gracias al AnimOffset.

Imagen tomada de https://docs.unrealengine.com/latest/INT/Engine/Animation/AnimHowTo/AimOffset/index.html donde se ve al personaje apuntando su arma en distintas direcciones sin rotar todo el cuerpo, gracias al AnimOffset.

Para simplificar un poco la implementación de nuestro mecanismo de apuntar haremos que en la horizontal el personaje simplemente rote en la dirección del controller, por esto fue que pusimos en true la propiedad del Character Use Controller Rotation Yaw. Más adelante vamos a “afinar” un poco más esto, para evitar que cuando el character esté apuntando en la horizontal rote patinando en el suelo, pero de momento es suficiente. Para apuntar en la vertical si vamos a hacer uso del AimOffset.

Creando un AimOffset

En el Content Browser selecciona Add New/Animation y verás que tenemos dos opciones AimOffset y AimOffset 1D. Tal como tenemos con los BlendSpace, en el AimOffset pasa lo mismo. Podemos crearlo para que tenga una sola entrada, por ejemplo, la rotación solo en un eje (AimOffset 1D), o para que tenga dos entradas. Aunque de momento vamos apuntar en la horizontal con el controller, vamos a crear el AimOffset de dos entradas (Aim Offset) para ver el proceso más complejo y ya dejarlo listo para cuando vayamos, más adelante, a mejorar el apuntar en la horizontal.

Después de crear el Aim Offset, dale un nombre y ábrelo para editarlo. Como verás su modo de edición es prácticamente idéntico a los BlendSpace (de hecho, los AimOffset son una especie de BlendSpace). Como ya ha estas alturas debes entender bien como funcionan los BlendSpace simplemente te dejo como tienes que configurar el AimOffset con las animaciones que nos brinda el PistolAnimsetPro. La característica que tienen los AimOffset a diferencia de los BlendSpace es que los primeros trabajan con animaciones de un solo frame, o sea, con poses, y es el propio Engine el que se encarga de hacer el blend entre los distintos poses según los valores de entrada para que el movimiento se vea fluido.

Captura del AimOffset en modo de edición. Los parámetros de entrada son la rotación que tendrá el controller en los ejes Yaw y Pitch y el rango de valores entre -90 y 90 es para evitar la torsión total del cuerpo.

Captura del AimOffset en modo de edición. Los parámetros de entrada son la rotación que tendrá el controller en los ejes Yaw y Pitch y el rango de valores entre -90 y 90 es para evitar la torsión total del cuerpo.

Primero configura los parámetros de entrada y el rango de valores como se muestra en la imagen, después arrastra los siguientes assets de animación al gráfico del AnimOffset comenzando de arriba hacia abajo y yendo de izquierda a derecha (recuerda usar la versión InPlace)

Pistol_AimOffset_LU
Pistol_AimOffset_CU
Pistol_AimOffset_RU
Pistol_AimOffset_LC
Pistol_AimOffset_CC
Pistol_AimOffset_RC
Pistol_AimOffset_LD
Pistol_AimOffset_CD
Pistol_AimOffset_RD

Abre cada uno de estos assets para que veas que son una animación de un solo frame y que representan el pose máximo en cada una de las direcciones en las que podrá apuntar el character. Hecho esto puedes mover el cursor sobre el gráfico, simulando la entrada de los valores, para que veas en el Preview como se comporta la animación. Salva y cierra el editor del AimOffset.

Gracias al PistolAnimsetPro los Assets necesarios para crear el AnimOffset ya estaban listos, pero te recomiendo que profundices un poco más con la documentación oficial de Unreal en las secciones Aim Offset y Creating an Aim Offset porque los Animation Sequence que se necesitan para cada pose tienen varios detalles importantes de configuración a tener en cuenta para que después estos assets los puedas usar en el AimOffset. También puedes revisar los ejemplos del Content Examples.

Bien, con estos dos assets listos podemos pasar a implementar la lógica en el EventGrapth del AnimationBlueprint para poder darle valor a las variables que servirán como valores de entrada a estos dos assets. Abre el AnimBlueprint del Character y crea las siguientes variables:

Speed (float): Para el BlendSpace del Idle/Run, será la velocidad del personaje.

PlayerAimYaw (float) y PlayerAimPitch (float): Serán la dirección de apuntar en cada eje, estos son los parámetros de entrada para el AimOffset.

Delta (float): Variable temporal para almacenar el DeltaTime y poderlo usar cómodamente en el script.

IsAiming (bool). Variable para saber si el personaje está apuntando o no, la inicializamos con la variable de mismo nombre que agregamos en el Character.

Una vez creada cada una de estas variables, implementa el siguiente algoritmo:

EventGraph del AnimBlueprint del Character para obtener los valores necesarios para pasar como parámetro al BlendSpace del estado Idle/Run y el AimOffset

EventGraph del AnimBlueprint del Character para obtener los valores necesarios para pasar como parámetro al BlendSpace del estado Idle/Run y el AimOffset

En este algoritmo no hacemos nada complejo, la velocidad la obtenemos a partir del Length del vector velocity del Character, como hemos hecho muchas veces ya y los valores para el Aim los obtenemos calculando la diferencia entre la rotación del Controller (la cámara) y la rotación del Character (mediante el nodo Delta (rotator)), suavizamos un poco el valor resultante mediante el nodo RInterp To para evitar saltos bruscos, y por último, limitamos esos valores entre -90 y 90 ya que son los valores extremos de entrada para el AimOffset para evitar la torsión total del cuerpo.

Solo un detalle curioso que seguro notarás y es ese 2.5 que restamos al Pitch y el 10 que sumamos al Yaw de la rotación del Controller. Esto lo hago para “forzar“ un poco la pose inicial del Character. Por defecto la pose inicial es apuntando totalmente hacia delante, pero si te fijas en la mayoría de los shooters el personaje está un poco hacia la izquierda de la pantalla y su pistola queda apuntando hacia el centro, lo que implica que tenga que estar un poco rotada hacia la derecha.
Después que terminemos, prueba quitar esos dos valores para que notes la diferencia en el pose del personaje con respecto a la mira (el centro de la pantalla).

Ahora crea un Montage a partir de la animación Pistol_ShootOnce. Este Montage lo usaremos para reproducirlo en el momento del disparo. Settea desde el editor la propiedad ShotPistolAnimation que creamos en el Character con este Montage. Por último pasa al AnimGraph y modifícalo para que te quede de la siguiente forma.

Captura del AnimGraph del AnimBlueprint del personaje después de agregar el Slot para poder reproducir el Montage del disparo, el Layered blend per bone, para blendear ese montage y solo reproducir esa animación en la parte de arriba del esqueleto y por último, antes de terminar en el Final Animation Pose, tenemos el AimOffset que creamos para lograr el movimiento al apuntar.

Captura del AnimGraph del AnimBlueprint del personaje después de agregar el Slot para poder reproducir el Montage del disparo, el Layered blend per bone, para blendear ese montage y solo reproducir esa animación en la parte de arriba del esqueleto y por último, antes de terminar en el Final Animation Pose, tenemos el AimOffset que creamos para lograr el movimiento al apuntar.

Aquí lo único nuevo que tenemos es que antes de terminar en el Final Animation Pose tenemos el nodo que representa el AimOffset que creamos anteriormente. Esto es lo último necesario para tener nuestro mecanismo de apuntar listo.

Guarda todo, compila y dale Play al juego. El personaje ya inicia en su pose de apuntar, si mueves el mouse en la vertical para girar el personaje rota en esa dirección y si mueves el mouse hacia arriba y hacia abajo verás como entra en juego el AimOffset haciendo que solamente rote el torso para apuntar en esa dirección, tal como haríamos en la vida real. Puedes probar poner en false la propiedad bUseControllerRotationYaw para que veas como se comporta el AimOffset al apuntar en la horizontal.

Captura de pantalla del juego donde se ve el personaje en su pose de apuntar.

Captura de pantalla del juego donde se ve el personaje en su pose de apuntar.

Bien, ya terminamos con el movimiento básico para nuestro personaje. Hay un detalle que seguro notarás, el Third Person Sample no tiene ese punto de mira en el centro de la pantalla. En realidad lo pedimos prestado del First Person Sample :) es muy simple. Crea un blueprint que herede de HUD y agrega lo siguiente (copia la textura del First Person Sample). No olvides modificar el GameMode para usar este Blueprint como HUD.

Simple método del HUD para dibujar una mira en el centro de la pantalla (Tomado del First Person Template)

Simple método del HUD para dibujar una mira en el centro de la pantalla (Tomado del First Person Template)

Solo nos va quedando agregarle un arma a nuestro personaje, verdad ?. Pero antes de implementar el arma vamos a implementar el proyectil que usará esa arma.

Anteriormente implementamos un mecanismo para disparar un arma y detectar la colisión del disparo con el enemigo, pero en ese caso lo hicimos un poco ficticio. Lo que hicimos fue que en el momento del disparo se haga un Line Trace para simular la trayectoria de la bala, y el primer Actor con el que colisione ese Line Trace es el actor que recibe el disparo. Este modo de disparo generalmente se conoce como “Instant Hit“ porque inmediatamente que se hace clic, se hace el trace y se detecta el impacto. Esa solución es totalmente válida y para nuestro caso se ajustaba perfectamente, pero no siempre esa es la solución que estamos buscando para este tipo de situación. En muchos casos necesitamos una implementación que se ajuste más a la realidad. Cuando se dispare el arma salga de esta un proyectil con una velocidad determinada, que sea afectado por la gravedad, que tenga cuerpo etc. Pues para esto tenemos un fenomenal componente que nos brinda Unreal Engine 4: el ProyectileMovementComponent.

Introducción al uso del ProjectileMovementComponent

El ProjectileMovementComponent es un componente que nos permite actualizar la posición del Actor en cada Tick simulando la trayectoria de un proyectil a partir de su velocidad y gravedad. También permite activar si queremos que rebote al impactar. Es muy útil cuando queremos implementar por ejemplo: un lanza granadas, el disparo de una pelota, o el disparo de una bala. Aunque no debemos abusar de su uso, ten en cuenta que sería un actor más en el escenario calculando física, render etc. Por ejemplo, los disparos de una ametralladora no son aconsejados hacerlos por esta vía, mejor usar el Instant Hit, por la cantidad de proyectiles que se tendrían que crear en runtime y todo el calculo de la física. En realidad, una pistola como la que estamos implementando ahora, también por lo general su disparo se implementa como instant hit, pero vamos a hacer la excepción aquí para poder ver como funciona este genial componente. Después, un buen ejercicio es que intentes hacer por tu cuenta la implementación Instant Hit para esta arma, y si tienes alguna duda puedes dejarme un comentario y vemos como solucionarlo 😉

Bien, lo primero que vamos a crear es el Actor que usaremos como proyectil de nuestra arma. Crea una clase en C++ de nombre AProjectile que herede de Actor. Agrégale un componente de colisión, un StaticMesh y un ProjectileMovementComponent. A continuación te dejo como te debe quedar, ve detenidamente por los comentarios, sobre todo los relacionados al ProjectileMovementComponent para que veas como es su inicialización.

//-------------------------------------------
// Projectile.h
//-------------------------------------------

#pragma once

#include "GameFramework/Actor.h"
#include "Projectile.generated.h"

UCLASS()
class THIRDPERSONSHOOTER_API AProjectile : public AActor
{
	GENERATED_BODY()

    /** Componente de colisión */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UBoxComponent* CollisionComponent;

    /** Mesh del proyectil */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UStaticMeshComponent* MeshComponent;

    /** Componente para lograr el movimiento del proyectil */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UProjectileMovementComponent* MovementComponent;

public:
	// Sets default values for this actor's properties
	AProjectile();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

    FORCEINLINE class UBoxComponent* GetCollisionComponent() const { return CollisionComponent; }

    FORCEINLINE class UStaticMeshComponent* GetMeshComponent() const { return MeshComponent; }

    FORCEINLINE class UProjectileMovementComponent* GetMovementComponent() const { return MovementComponent; }
};

//-------------------------------------------
// Projectile.cpp
//-------------------------------------------

#include "ThirdPersonShooter.h"
#include "Projectile.h"

AProjectile::AProjectile()
{
 	//Settea este actor para que se llame el método Tick() en cada frame
	PrimaryActorTick.bCanEverTick = true;

    //Crea el componente de colision como el RootComponent de este Actor
    CollisionComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("CollisionComponent"));
    RootComponent = CollisionComponent;

    //Crea el componente para el Mesh del proyectil y lo ancla al RootComponent
    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
    MeshComponent->AttachTo(RootComponent);

    //Crea el UProjectileMovementComponent para el movimiento del proyectil
    MovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("MovementComponent"));

    //Fíjate que el MovementComponent no se ancla a ningun otro componente, en cambio lo que se hace es definir cual será el componente
    //que se moverá a partir de la configuración de este, en este caso es el rootcomponent el que queremos afectar.
    MovementComponent->UpdatedComponent = CollisionComponent;

    //Velocidad iniciar que tendrá el proyectil al ser agregado a la escena
    //En realidad un proyectil se movería mucho más rápido, pero vamos a quedarnos de momento con este valor para poder ver su recorrido
    MovementComponent->InitialSpeed = 2000.0f;

    //Máxima velocidad que podrá alcanzar
    MovementComponent->MaxSpeed = 2000.0f;

    //Con bRotationFollowsVelocity en true, hacemos que la rotación sea actualizada en cada tick para q empareje con vector de velocidad
    MovementComponent->bRotationFollowsVelocity = true;

    //El valor de gravedad que afectará al proyectil, en este caso no queremos que sea afectado por la gravedad.
    MovementComponent->ProjectileGravityScale = 0.f;
}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
	Super::BeginPlay();

}

// Called every frame
void AProjectile::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}

Compila y abre el editor, crea un nuevo Blueprint que herede de la clase AProjectile que acabamos de crear, nómbralo BP_Projectile. Ábrelo para editarlo y en el StaticMeshComponent settea un mesh que será el cuerpo del proyectil, como no tenemos ningún recurso en forma de bala, puedes usar una esfera escalada o cualquier otro mesh semejante. Ajusta las propiedades del Collision Component y la posición del Mesh dentro de este.

Selecciona el ProjectileMovementComponent y dale un vistazo a las propiedades que puedes modificar desde acá, verás que por defecto los valores de velocidad y gravedad ya están configurados con los números que le dimos en C++.

Pudiera darse el caso que quisiéramos que nuestro proyectil se comportara más como una pelota, por ejemplo, como sucede en el Template First Person. En este caso solo tienes que disminuir el valor de la propiedad InitialSpeed y MaxSpeed para que salga disparado a menos velocidad y aumentar el valor de la propiedad GravityScale, para que la gravedad lo haga caer al suelo mucho más rápido. Puedes crear un proyecto basado en la platilla del First Person y revisar los parámetros del blueprint del proyectil en ese proyecto para que veas su comportamiento en el juego.

Finalmente el BP_Proyectile te debe quedar así.

BP_Projectile. En este caso el Mesh del proyectil brilla tanto por el material que tiene aplicado, lo hice así para poderlo ver mejor al ser disparo. En tu caso, te repito, puedes usar cualquier Mesh incluso sin material.

BP_Projectile. En este caso el Mesh del proyectil brilla tanto por el material que tiene aplicado, lo hice así para poderlo ver mejor al ser disparo. En tu caso, te repito, puedes usar cualquier Mesh incluso sin material.

Pues bien, ya con el proyectil listo, solo nos queda el arma.

Implementando la pistola que usará nuestro personaje

Primero vamos a crear la clase base de todas las armas que tendremos en nuestro juego.

//-------------------------------------------
// Weapon.h
//-------------------------------------------

/** Clase base de todas las armas */
UCLASS()
class THIRDPERSONSHOOTER_API AWeapon : public AActor
{
	GENERATED_BODY()

private:

    /** Mesh del arma */
    UPROPERTY(VisibleDefaultsOnly, Category=Mesh)
    USkeletalMeshComponent* Mesh;

protected:

    /** Get del Mesh **/
    FORCEINLINE USkeletalMeshComponent* GetWeaponMesh() const { return Mesh; }

public:

	/** Constructor */
    AWeapon(const FObjectInitializer& ObjectInitializer);

	/** Es llamado por el engine cuando este actor es agregado al juego */
	virtual void BeginPlay() override;

	/** Se llama en cada frame */
	virtual void Tick( float DeltaSeconds ) override;

    /** Retorna el posición del socket MuzzleFlash. La punta del cannos del arma */
    FVector GetMuzzleLocation() const;

    /**
     * Método virtual puro, nunca tendrá implementación en esta clase, se tiene que implementar en las clases base
     * Tendrá la lógica de disparo de cada arma
     */
    virtual void FireWeapon() PURE_VIRTUAL(AShooterWeapon::FireWeapon,);

};

//-------------------------------------------
// Weapon.cpp
//-------------------------------------------

#include "ThirdPersonShooter.h"
#include "Weapon.h"

AWeapon::AWeapon(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    //Inicialización del Mesh como RootComponent de este actor
    //Fíjate que le desactivamos la colisión a este mesh, de esta forma evitamos que un disparo pueda colisionar con el arma
    //a menos que quieras implementar algún mecanismo en el que si esto pasa, el personaje suelte el arma 😉
    Mesh = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("WeaponMesh"));
    Mesh->SetCollisionObjectType(ECC_WorldDynamic);
    Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
    Mesh->SetCollisionResponseToAllChannels(ECR_Ignore);
    RootComponent = Mesh;
}

FVector AWeapon::GetMuzzleLocation() const
{
    USkeletalMeshComponent* UseMesh = GetWeaponMesh();
    return UseMesh->GetSocketLocation(FName(TEXT("MuzzleFlash")));
}

// Called when the game starts or when spawned
void AWeapon::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void AWeapon::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );
}

Como ves, es una clase muy simple que hereda de Actor y de extra solo le agregamos el método GetMuzzleLocation que nos devuelve la posición del socket en la punta del cañón del arma.

Ahora crea otra clase que herede de esta clase AWeapon y vamos a llamarla APistol. Esta clase APistol será la clase para la pistola que usará nuestro personaje. Tendrá un atributo que será una estructura que crearemos para almacenar en ella la información del tipo de proyectil que usará. De esta forma nos quedará muy fácil si en el futuro queremos cambiar el tipo de proyectil que usa el arma. Además de esto, tendrá la implementación del método FireWeapon con toda la lógica necesaria para calcular la dirección en la que se tiene que hacer el Spawn del proyectil para que salga disparado en la dirección exacta a la que estamos apuntando.

//-------------------------------------------
// Pistol.h
//-------------------------------------------

#pragma once

#include "Weapon.h"
#include "Projectile.h"
#include "Pistol.generated.h"

/**
 * Estructura para encapsular la información del projectile que usa cada arma
 * Cada arma tendrá una instancia de esta estructura, que se podrá editar desde el Editor para facilmente configurar la información de su proyectil
 */
USTRUCT()
struct FProjectileData
{
    GENERATED_USTRUCT_BODY()

    /** Clase del proyectil. Necesario para el momento de hacer el Spawn */
    UPROPERTY(EditDefaultsOnly, Category="Defaults")
    TSubclassOf<class AProjectile> ProjectileClass;

    /** Damage que causará este proyectil al impactar */
    UPROPERTY(EditDefaultsOnly, Category="Defaults")
    float Damage;

    /** Constructor por default de la estructura */
    FProjectileData()
    {
        ProjectileClass = NULL;
        Damage = 100;
    }
};

UCLASS()
class THIRDPERSONSHOOTER_API APistol : public AWeapon
{
	GENERATED_BODY()

protected:

    /** Info del proyectil que usará esta arma */
    UPROPERTY(EditDefaultsOnly, Category=Config)
    FProjectileData ProjectileConfig;

public:

    /**
     * Dispara el arma
     * Calcula la posición y rotación en la que debe de hacerse el Spawn del proyectil para que salga en la dirección a la que estamos apuntando
     */
	virtual void FireWeapon() override;
};

//-------------------------------------------
// Pistol.cpp
//-------------------------------------------

#include "ThirdPersonShooter.h"
#include "Pistol.h"

void APistol::FireWeapon()
{
    //TODO: Implementar el disparo
}

Con estas clases creadas, compila, abre el editor y crea un blueprint a partir de esta clase, yo le llamé BP_Pistol. Como SkeletalMesh selecciona la pistola que viene en el Military Weapon Silver y fíjate que gracias al atributo Projectile Config que creamos en C++ como EditDefaultsOnly. Desde acá podemos definir el proyectil que usará esta pistola, junto con el Damage que causará.

BP_Pistol configurado con el Mesh de la pistola que viene en el Military Weapon Silver Pack y para usar como proyectil el BP_Projectile que creamos previamente

BP_Pistol configurado con el Mesh de la pistola que viene en el Military Weapon Silver Pack y para usar como proyectil el BP_Projectile que creamos previamente

Ahora, para comprobar que todo está bien, vamos desde el BeginPlay ha equiparle el arma a nuestro personaje. Abre el blueprint del character, en el BeginPlay usa el nodo Spawn Actor From Class (que nos permite agregar un actor a la escena en tiempo de ejecución) para hacer un Spawn de la pistola y anclarla a la mano del personaje. Fíjate que en este caso es importante settear como el Instigator del arma al Character (self) . . . Ups y casi se me olvida :), debemos agregar en la clase del Character un atributo de tipo AWeapon para tener en todo momento una referencia al arma que está usando. Abre la .h del Character y agrégale el siguiente atributo (Recuerda incluir la .h de AWeapon):

/** Arma actualmente equipada */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Weapon")
class AWeapon* CurrentWeapon;

Listo !! ahora si podemos equiparle el arma a nuestro Character en el Begin Play

BeginPlay del Character, donde se hace un Spawn del arma, se inicializa el CurrentWeapon del Character y se ancla la pistola a la mano.

BeginPlay del Character, donde se hace un Spawn del arma, se inicializa el CurrentWeapon del Character y se ancla la pistola a la mano.

Muy bien, con esto ya tenemos nuestro personaje caminando por el escenario con la pistola en la mano, solo nos queda implementar el mecanismo para disparar el arma. Ve al Pistol.cpp y sustituye el método FireWeapon que dejamos pendiente por implementar por el siguiente:

void APistol::FireWeapon()
{
    //El Origen del disparo es la punta del cannon de la pistola (la posición del socket "MuzzleFlash")
    FVector Origin = GetMuzzleLocation();

    //Ahora vamos a determinar la rotación inicial que le daremos al proyectil para que salga disparado hacia donde estamos apuntando.
    //Para determinar esta rotación, primero tenemos que hacer un Trace hacia donde está "mirando" la camara
    //para obtener la posición exacta del objeto al que estamos apuntando (el objeto con el que colisione ese Trace)
    //y con esta posición, podemos calcular la rotación que le tenemos que dar al proyectil para que vaya en esa dirección.

    //Primero vamos a obtener el punto de inicio del Trace

    FVector ShootDir = FVector::ZeroVector;
    FVector CamLocModified = FVector::ZeroVector;

    //El Instigator de un actor es el responsable del Damage causado por este actor. Por lo general se settea al hacer el Spawn del actor
    //A partir del Instigator de la pistola, que será nuestro Character, obtenemos el Controller para poder obtener el punto de mira de la camara
    APlayerController* const PlayerController = Instigator ? Cast<APlayerController>(Instigator->Controller) : NULL;

    if (PlayerController)
    {
        FVector CamLoc;
        FRotator CamRot;

        //GetPlayerViewPoint del PlayerController retorna en CamLoc la posición de la cámara y en CamRot la rotación
        PlayerController->GetPlayerViewPoint(CamLoc, CamRot);
        ShootDir = CamRot.Vector();

        //Ahora vamos a desplazar el vector CamLoc para que quede a partir del character y en la dirección a la que estamos mirando
        //para poder hacer un Trace en dirección a donde estamos mirando sin que nuestro Character bloquee ese Trace por estar en el medio

        FVector Diff = ((Instigator->GetActorLocation()) - CamLoc);

        float DotProductResult = FVector::DotProduct(Diff, ShootDir);

        CamLocModified = CamLoc + (ShootDir * DotProductResult);
    }

    //Ahora tenemos que hacer un LineTrace desde la posición que acabamos de calcular, en dirección a donde estamos apuntando,
    //para predecir el punto de impacto que tendrá el proyectil y poder calcular la rotación que le tenemos que dar para que vaya en esa dirección.

    const float WeaponRange = 10000.0f; // Un valor grande que básicamente sería el alcance del proyectil

    const FVector EndTrace = CamLocModified + ShootDir * WeaponRange;

    FCollisionQueryParams TraceParams;
    FHitResult Impact(ForceInit);
    GetWorld()->LineTraceSingleByChannel(Impact, CamLocModified, EndTrace, ECC_GameTraceChannel1, TraceParams);

    //Finalmente el ajuste de rotación del proyectil para que al hacerle el spawn vaya en esa dirección
    //El vector resultante de la resta entre el punto de impacto y el origen, normalizado, nos da ese vector de dirección que buscamos
    if (Impact.bBlockingHit)
    {
        ShootDir = (Impact.ImpactPoint - Origin).GetSafeNormal();
    }

    //Listo !! ... ya tenemos los dos vectores que necesitamos, origen y rotación, ahora solo queda hacer el Spawn del proyectil

    //Creamos el FTransform para el Spawn del proyectil
    FTransform SpawnTransform(ShootDir.Rotation(), Origin);

    //Iniciamos el Spawn. Fíjate que la Class que le pasamos es lo que setteamos en ProjectileConfig.ProjectileClass
    //Esta clase la vamos a cargar desde el Editor en las propiedades del Blueprint de la pistola y será el BP_Projectile que creamos a partir de la clase AProjectile
    AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginSpawningActorFromClass(this, ProjectileConfig.ProjectileClass, SpawnTransform));
    if (Projectile)
    {
        UGameplayStatics::FinishSpawningActor(Projectile, SpawnTransform);
    }
}

Es muy importante que vayas detenidamente por los comentarios del método porque para poder garantizar que al hacer el spawn del proyectil, este vaya exactamente en dirección a donde estamos apuntando, necesitamos de un poco de matemáticas y Traces :).

Lo que hacemos en el método es determinar la rotación inicial que le daremos al proyectil para que salga disparado hacia donde estamos apuntando. Para determinar esta rotación, primero tenemos que hacer un Trace hacia donde está “mirando” la cámara para obtener la posición exacta del objeto al que estamos apuntando (el objeto con el que colisione ese Trace) y con esta posición, podemos calcular la rotación que le tenemos que dar al proyectil para que vaya en esa dirección. Una vez que tenemos la posición y la rotación del proyectil solo tenemos que hacerle un Spawn en el nivel y del resto se encarga el ProjectileMovementComponent 😉

La línea Roja es una línea recta desde la punta de la pistola, como vez esa no puede ser la dirección que siga el proyectil. La línea azul es el Trace que hacemos para determinar la posición del objeto al que estamos mirando y por último, la línea verde representa la trayectoria que seguirá el proyectil después de ajustar su rotación inicial.

La línea Roja es una línea recta desde la punta de la pistola, como vez esa no puede ser la dirección que siga el proyectil. La línea azul es el Trace que hacemos para determinar la posición del objeto al que estamos mirando y por último, la línea verde representa la trayectoria que seguirá el proyectil después de ajustar su rotación inicial.

Por último, abre la clase del Character y agrega el método que disparará el arma que tengamos equipada. Recuerda llamar este método desde algún InputAction.

void AUnrealMannequin::FireWeapon()
{
	if(CurrentWeapon)
    {
        //Play a la animación de disparo
        PlayAnimMontage(ShotPistolAnimation);

        //Fire del arma
        CurrentWeapon->FireWeapon();
    }
}

Listo !! Compila y dale Play al juego. Dispara el arma y verás que en el momento en el que tocamos la tecla de Fire, además de la animación del personaje, sale disparado el proyectil desde la punta del cañón y exactamente hacia la dirección en la que estamos apuntando, justo como si se tratara de un proyectil real 😉

Captura del juego en ejecución donde se ve después de hacer el disparo, el proyectil “spawneado “ en la escena desde la punta del cañón y moviéndose en dirección a donde estamos apuntando.

Captura del juego en ejecución donde se ve después de hacer el disparo, el proyectil “spawneado “ en la escena desde la punta del cañón y moviéndose en dirección a donde estamos apuntando.

Terminado por hoy . . .

Vamos a dejar este tutorial hasta aquí. Verdad que aún no hemos visto nada de multiplayer, que es el plato fuerte de la serie, pero antes necesitábamos de todo este mecanismo inicial. En el próximo tutorial comenzaremos ya con el multiplayer. Este mismo sistema de disparar el arma vamos a hacerlo funcionar en multiplayer, así que no te vayas muy lejos . . . mientras, como siempre, me encantaría escuchar tus comentarios 😉

Making a 3D side-scroller game in UE4

Introduction

Let’s start summing up what we did in the previous tutorial. We started our series with a general introduction to Unreal Engine 4 through a project which explores some of the basic concepts of the engine. We saw the framework’s class hierarchy, the visual scripting, the character animation settings, and we defined a fixed camera as a temporary solution in our game, among other things. If you haven’t already read the previous tutorial, I strongly suggest you do before continuing with this one.

In this tutorial, we will create the base to our 3D side-scroller game’s style. Currently my team and I are working on an automatic Runner, 2D side-scroller for IOS and Android. You can follow us on our Facebook page to keep up with our work in progress and to know when it will release. If you like this kind of game, I can assure you that you will love ours ;).

As I already said, in this tutorial we will configure our game camera to achieve a side-scroller view. We will also add some coins to our scene and use simple collision mechanism that will allow the character to collect the coins. We will “teach” our character to run and jump :). We will also see some variable and function macros for the integration between the C++ code and the Editor… and so much more. Are you ready?!… Well let’s get started!!

Setting the level from the editor

Let’s start by making a small change to the current level through the editor to match the style of game that we want. The base to a side-scroller game is to have the camera parallel to the main character and to have the camera a certain distance away from the character on the y axis. The character moves only in two directions – upward and downward when he jumps, and left/right when he walks.

Open in the Editor the UE4Demo project that we used in the last tutorial and delete the visible objects that we won’t use (the chairs, the table, the statue, etc.), leaving only the floor object. After that, modify this object using the transformation and escalate tools situated in the upper-right corner of the viewport. Then create copies of the object, modify them indistinctly and spread them through the level. Make sure to leave the ‘Actor Play Start’ on one of the platforms, to avoid that the character free fall into abyss. This is how I did it (use your imagination to achieve a better result than mine :).

Modified level in the Editor to match our game style

Modified level in the Editor to match our game style

 

As you will notice, when the game runs, it shows a red alert which says: LIGHTING NEEDS TO BE REBUILT. This alert has to do with the fact that we change the level geometry and the engine needs to rebuild the light so the illumination and shadows fit the new geometry. You can rebuild the lights selecting the Toolbar/Build/Build Lighting Only option. Run again and you will notice that everything goes back to normal.

For now we have a very basic level but enough to implement and test all the things that we have planned to do.

Configuring the camera for a side-scroller game.

At this point, it’s important to clarify that UE4 has a default template to build this style of game. In fact, we will use practically the same elements that this template uses but the idea of this tutorial is to do it from scratch to understand the basic concepts of the game style.

First we will change the game camera. In the last tutorial, we configured a simple fixed camera that served the purpose of introducing us both into the visual scripting (Blueprint Editor) and the C++ code. We will no longer use this camera so go ahead and delete the current implementation of the camera both in code and in the Blueprint Editor. If you still have the code implementation, comment out the lines inside the Begin Play method. In the Blueprint you may delete all the nodes or, if you want to keep the references, delete the connection leaving the BeginPlay node. By deleting this connection, we break the camera algorithm because the execution doesn’t continue when the BeginPlay event is executed but we still hold the rest of the connections and references.

Let’s configure a new camera’s style, this time through code in our Character’s class. Always take into account that you can also do it through the Editor. Remember that we have a Blueprint class that inherits our HeroCharacter class. A good way to practice will be for you to adventure by yourself once we do it by code to do the same in the Editor by modifying the HeroCharacterBlueprint.

Open the HeroCharacter class and add the next declarations after the GENERATED_UCLASS_BODY() macro:


/** Spring arm to fix the camera to the Character to match the side-scroller style */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<USpringArmComponent> SpringArm;
    
/** Game camera, is attached to the arm’s socket to achieve the side-scroller’s camera style */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<UCameraComponent> SideViewCamera;

We add two class variables to our HeroCharacter, but I’m sure that the thing that caught your attention was the UPROPERTY macro included for each variable. This way we define whether or not we want to use these attributes in the Editor and what options we have to work with them. As we saw in the previous tutorial, one of the coolest things about UE4 is the seamless integration between the code and the editor and this macro is one of the powerful utilities to achieve it. Next, let’s look at some of this macro’s parameters:

VisibleAnywhere: Defines if this property will be visible in the Editor’s property panel.

BlueprintReadOnly: Defines if this property could be read from VisualScript in the Blueprint, but it can’t be modified.

Category: Allow to specify a category name under the properties will be listed in the Editor.

You can find a detailed reference of all of the configurable parameters to the UPROPERTY macro in the Runtime/CoreUObject/Public/UObject/ObjectBase.h inside the UP namespace. If you click over a category while pressing the cmd key in MACOS, or click one while holding ctrl in Windows, you will be taken to the specific reference for that macro.
After we implemented the constructor where we initialized these variables, go to the Editor to check the result of defining the attributes with this macro.

These two class attributes just created in HeroCharacter are of a data type we haven’t used before. The first one is USpringArmComponent that we named SpringArm. Notice that we used the parametrized TSubobjectPtr class to define it. This way we can use the CreateDefaultSubobject method of the PCIP object received in the constructor to create an instance of any data type, which we will in a second. The USpringArmComponent allows us to fix a component to its parent in a fixed distance. We will use this component to fix the game’s camera with a certain distance from the character.

We will also create the class attribute SideViewCamera of UCameraComponent data type. The class name is quite descriptive. This attribute is our game camera :).

Next we will initialize this variable in the class constructor. Open the HeroCharacter.cpp and add the following code block:


//Initializing the USpringArmComponent attribute
SpringArm = PCIP.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
   
//Adding the springArm to the Character's RootComponent (the collision capsule)
SpringArm->AttachTo(RootComponent);
   
//bAbsoluteRotation allows us to define if this support will rotate with the player or will stay fixed.
//In our case we don't want it to rotate with the character.
SpringArm->bAbsoluteRotation = true;
   
//The distance between the arm and its target. This value defines the distance between the character and the camera.
//Try out different values to see the outcome.
SpringArm->TargetArmLength = 500.f;
   
//Socket Offset.
//Socket is an anchor point to other components.
//For instance, in the character case we can define the socket in the character's hand
//this way we can add another component(for example a gun).
//But in our case we will add a camera to our SpringArm
SpringArm->SocketOffset = FVector(0.f,0.f,75.f);
   
//The relative rotation of the arm regard to its parent.
//We want the camera rotated 180 degrees in the Y axis in order to be situated parallel to the character, at the same level.
//This way we achieve the classic side-scroller camera's style.
SpringArm->RelativeRotation = FRotator(0.f, 180.f, 0.f);
   
// Creating the UCameraComponent instance.
SideViewCamera = PCIP.CreateDefaultSubobject<UCameraComponent>(this, TEXT("SideViewCamera"));
   
//The AttachTo method allow us to add an object to another in a given socket. It receives two parameters,
//the first one, the object where we will be anchored (the springArm) and the second the socket's name where we will be anchored.
//USpringArmComponent's SocketName returns the name of the components socket.
SideViewCamera->AttachTo(SpringArm, USpringArmComponent::SocketName);

Pay attention to each line comments so you can understand what each stands for. Overall, we create and configure the USpringArmComponent’s object and then we add it to the Character. Next, we create and configure the UCameraComponent’s object (the game camera) and add it to the USpringArmComponent to fix it to a given distance from the Character. Notice that we create the instances with the received reference in the constructor class using PCIP.CreateDefaultSubobject.

Ready, build and play the game. Now you have the game view in the side-scroller style :). Try to move in the level just created to see how the camera follows your every moment, always at a fixed distance.

New game view configuration to match the side-scroller camera's style

New game view configuration to match the side-scroller camera’s style

 

Don’t close the editor. Let’s focus in HeroCharacterBlueprint. In the last tutorial, we created this blueprint in the Character folder. Open it and activate the Components mode (upper-right corner). Notice that now in the Character’s Components panel we have a new object: the SpringArm and it contains a child the SideViewCamera. Check out all the properties defined by code. You can also check all the default properties values, change the values, and check out the different outcomes.

To test the parameters effect of the UPROPERTY macro in practice, go back to the code and delete the VisibleAnywhere parameter set in the property and build again. When you open the HeroCharacterBlueprint in the editor, in spite of seeing the components, we can’t see the properties values in the details panel when we select them.

Modifying the game controls for a side-scroller’s game.

So far we have set the camera’s style but I’m sure you noticed that the game controls don’t fit our game’s style, given that the character can move both in X and Y axis which is very unusual in a side-scroller game. Therefore we’ll change the game controls a bit to adjust them to the side-scroller style. We will also add two new actions and controllers to our character: run and jump.

I assume that after the last tutorial you have a couple of ideas of how to add these actions. In the Editor, select Edit/Project Settings/Input and leave only the MoveRight entry. Now let’s add another input type the ActionBinding. These entries, unlike the AxisBinding entries, are used to execute specific actions e.g. to jump or open a door. Create a new entry of this data type and name it Jump. Select the space bar as the key control. If you look closely you will notice that we can also define that the action gets executed when two keys are pressed simultaneously. In this case, will only use the space bar to jump.

New configuration of the game's controls. Adding jump control.

New configuration of the game’s controls. Adding jump control.

 

Now let’s code. First of all, we no longer need the MoveForward method of the HeroCharacter class. Delete the method statement in the .h and the implementation in the .cpp. Also, in the SetupPlayerInputComponent method, delete the MoveForward BindAxis. Lastly, we have to modify the MoveRight implementation given that at the moment when the entry gets called we rotate the character position, now we want that the character to move forward and backward respectively. Modify the MoveForward as the code below:


/**
*  Gets called when the MoveForward entry is detected (When the user press the A or D keys).
*  @param Value Value is equal to 1 when the D is pressed and -1 when A is.
*/
void AHeroCharacter::MoveRight(float Value)
{
if ( (Controller != NULL) && (Value != 0.0f) )
{
        // Adds a new movement to the right or left according to the Value value.
        AddMovementInput(FVector(0.f,-1.f,0.f), Value);
}
}

Now this method is much simpler and I hope it’s easier to understand what it does. Anyway, I will explain step by step what we just did. We apply a movement vector that affects only the y axis of the vector’s value. So when the user presses the D key, the character will move forward (to the right) and when the A key is pressed, the character will move backward, meaning to the left side.

Now we have to implement the method that will get called to execute the jump action when the user presses the space bar. It’s very simple. Just add the next line to the SetupPlayerInputComponent method:

InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);

Notice one thing, the method that gets called is the ACharacter::Jump. Jump is a method implemented in our base class, not in our own class HeroCharacter. This method already has all that we need to make the character jump. It’s really amazing how much help the framework provides us with :).

Go ahead build and play the game. Press the A and D keys to see how the character moves correctly on the scene, and how when you press the W and S keys, nothing happens. Hit the space bar and you will see how our character now also jumps :) … but something is still missing. Yes the character is jumping but visually is playing the walk animation. Next thing we need to do is add the jump animation.

Setting the jump animations for the character

Since the last tutorial, we have the main character resources that supposedly our design team have us, among them we have three FBX animations to jump: the Jump_End.FBX, Jump_Loop.FBX, Jump_Start.FBX and the Run.FBX file. Import them in the Animation folder. You can inspect them in the Persona Editor.

I’m sure that the fact that we have three different animations for the jump caught your attention, and you ask yourself, “Why??”. I will give you the answer right away but first let me share a personal experience with you involving this aspect: When we start the development of our current project, you can take a look in here :)). We struggle with this problem.
In our game, the character jumps at different heights. For instance, it can do a small jump to avoid a box or a long jump from a cliff and stays longer in the air. The problem is that in the long jump case we play the jump animation when the action is started with a duration and might end while the character is still in the air falling in the last frame of the jump animation until it touches the ground where the transition will continue normally. That’s the reason why in many cases, it’s necessary to divide the jump animation in three pieces, we have the start jumping action then we have a loop animation that is played while the character is falling and finally the animation when the character touches the ground. This is how we achieve the whole jump animation cycle independently of the height.

Let’s configure it in the character animation blueprint. As we saw in the last tutorial, we use a state machine for the animation system that allows us to separate the different states that our character supports and set an animation for each state. Currently the state machine of our character is very simple, containing only the Idle state and the Walking state. Let’s add the jumping states.

Inside the HeroAnimBlueprint/AnimGraph, enter the state machine, drag the cursor from the Idle/Walk node to create a new node, and name it JumpStart. Repeat the procedure twice using the last created node to create the JumpLoop node and finally the JumpEnd. At the end, connect the JumpEnd state to Idle/Walk to close the cycle. It should look like this:

New Character state machine, with the jumping states added

New Character state machine, with the jumping states added

 

We have just defined three new states to our character and the order in which they would be reached. In other words, the character could be in rest or running and can change to the JumpStart state (jump starts). From the JumpStart state, he can reach the JumpLoop (loop cycle) and then the JumpEnd state. Lastly, he could go to the Idle/Walk state. Notice the directional arrows between the states. These are the connections that define the origin and destination states. If you jump you will notice the four states and the blending between them.

Each state has an icon over the transition arrow. This icon represents the condition that triggers the transition between the states. We have to define this condition using the visual scripting in the Blueprint Editor. The first case is when the character is in the Idle/Walk state and starts the jump action. The condition to pass to this state will be BOOL variable that will store if the character is in the air or not. When the character changes the state such that it is in the air, we will change to the JumpStart state.

Double click in the transition icon to enter in its edition mode. By default we have a Result node with the “Can Enter Transition” description. This node expects a bool parameter that the state machine will use to decide if the state transition takes place. Create and add a new variable like we did in the last tutorial but this time use bool as data type. Name it IsInAir or any name that you prefer but it must be something meaningful. Add it to the blueprint in GET mode and finally connect this node output port to the input port of the Result node. So if the IsInAir variable has a true value, the transition will execute and the character will pass to the JumpStart state.

VisualScript of the transition between the Idle/Walk and JumpStart

VisualScript of the transition between the Idle/Walk and JumpStart

 

Save and exit the edition mode of the transition between the Idle/Walk and JumpStart and enter the edition mode of the JumpStart node to define which animation will be played in this case. Drag the JumpStart animation from the resources folder into the blueprint and connect it to the final node. The JumpStart and JumpEnd animations will be played only once which is different to what we did in the last tutorial where the Idle and walk animations are played in a loop. The idea is to start playing the JumpStart then pass to the JumpLoop that as its name suggest plays in a loop and finally play the JumpEnd animation only once. So select the JumpStart animation and in the property panel, uncheck the Loop option. Do the same for the JumpEnd animation.

VisualScript of JumpStart node

VisualScript of JumpStart node

 

Now we have to define the condition to pass from the JumpStart to the JumpLoop animation. For this task we will use a new node. We need to be able to detect when the JumpStart animation is about to end to know when to start playing the loop animation. Double click in the transition icon between JumpStart and JumpLoop. Once again we meet the Result node that we’re about to use but first we need to do an algorithm to define when the animation is near to end.

Let’s add a new node of the Time Remaining (Ratio) type to the Jump_Start Asset. This node informs us of how much time remains before the animation ends. Let’s add another node < float type, we will use it to know if an A parameter is smaller than a B one. Connect the output port of the TimeRemaining node to the upper input port of the comparison. For the second input port, we will use a manual value, in this case 0.1. Now,when the TimeRemaining is less than 0.1 (the animation is about to end), we transition to the JumpLoop state. In order to complete the transition setup, we still have to connect the comparison node output to the Result node. It should look like this: [caption id="" align="alignnone" width="630"]VisualScript of the transition between JumpStart and JumpLoop animationsVisualScript of the transition between JumpStart and JumpLoop animations[/caption]

 

Summing up, we periodically check if the StartJump animation is about to end by checking if the remaining time is less than 0.1. When this condition is fulfilled, the transition is executed.

Save and exit the transition’s edition mode and enter the state JumpLoop edition mode. Add the JumpLoop animation and connect it to the Result. Unlike with the JumpStart animation, with the JumpLoop animation, we need to play it in a loop because this is the one that plays while the character is falling, so check that the loop option is checked.

JumpLoop's node VisualScript

JumpLoop’s node VisualScript.

 

Let’s configure the last transition between the JumpLoop and JumpEnd nodes. JumpEnd, as its name suggests, is the animation played when the jump ends. The condition to transition to this state is that the character is close to the floor (it’s no longer in the air). That’s exactly what the isInAir variable represents. Double click on the transition icon between JumpLoop and JumpEnd and add the isInAir variable as GET. The problem is that we need to know when the character isn’t in the air so we need to use the isInAir negation, so we will add a NOT node type to the blueprint. This node type returns the input’s negation. Connect the NOT node to the isInAir node and this to the Result. Now, as soon as the character hits the floor, the character will transition to the JumpEnd state.

VisualScript of transition between JumpLoop and JumpEnd

VisualScript of transition between JumpLoop and JumpEnd.

 

Exit the transition’s edition mode and enter in the JumpEnd edition mode. Drag and connect to the Final Pose the JumpEnd animation and uncheck the loop option.

JumpEnd's node VisualScript

JumpEnd’s node VisualScript

 

Finally, we have to define the condition for when to transition back to the Idle/Walk state coming from the JumpEnd state. This animation represents the character already on the floor but still recovering from the fall. We need to wait until the JumpEnd animation is about to end to change to the initial state (Idle/Walk). Basically, we will repeat the steps we use in the transition between the JumpStart and JumpLoop. I hope you are able to do it by yourself… 😉 it should look like this:

VisualScript of transition between JumpEnd and Idle/Walk

VisualScript of transition between JumpEnd and Idle/Walk

 

Now we have completed the character state machine, but a small detail is still missing. We need to set the IsInAir variable value like we did earlier with the Speed variable.

Close the AnimGraph Editor and open the EventGraph. Add a GetMovementComponent node and connect the TryGetPawnOwner node that we created in our last tutorial to the input port of the GetMovementComponent node. Add another node and name it IsFalling and connect its output port of GetMovementComponent to the new node’s input port. Add the IsInAir variable in SET mode and connect the IsFalling output to the IsInAir input. Finally, connect the blank output port of the SET Speed to the SET IsInAir input for the algorithm continuity.

HeroAnimBlueprint's EventGraph modify it to set the IsInAir variable value when the character is in the air

HeroAnimBlueprint’s EventGraph modified to set the IsInAir variable value when the character is in the air

 

If you have read the previous tutorial, I’m sure you won’t have any problem understanding what we just did. We got the character’s MovementComponent, which contains an IsFalling method that returns a bool value denoting if the character is in the air or not. This IsFalling method is the one we will be using to set our IsInAir variable. Now we have the state machine for our character. Build the AnimationBlueprint and run the game. Press the space bar … now our hero jumps too :).

Character jumping with proper animation

Character jumping with proper animation

 

Implementing character’s running mechanism!!

Now our character knows how to walk, rest and jump, but a classic feature in side-scroller games is the ability to run to get more momentum and jump higher and further. Who doesn’t remember in one of Super Mario latest level the huge hole that can only be jumped with a great momentum, do you :)… So the next thing we will do is to add this skill to our character. Let’s implement it so that when the character is walking and the Shift key is pressed, the character will run.

First of all, open the editor and in the controls sections, add a new ActionBinding entry, name it Run and select the LeftShift key. Close the editor and open the HeroCharacter.cpp inside the SetupPlayerInputComponent method and add the following two lines:


//The Run entry is detected, when the Shift key is pressed we set that the ToggleRunState method should be call.
InputComponent->BindAction("Run", IE_Pressed, this, &AHeroCharacter::ToggleRunState);
   
//The Run entry is detected, when the Shift key is released we set that the ToggleRunState method should be call.
InputComponent->BindAction("Run", IE_Released, this, &AHeroCharacter::ToggleRunState);

Notice a tiny detail in this code. We are setting the BindAction for the Run entry twice and passing the same ToggleRunState method (that we will soon implement). The difference between the calls is that the second parameter specifies when the method gets called. The first case, IE_Pressed is fulfilled when the Shift key is pressed and IE_Release when it’s released. What we want to achieve is that when the key is pressed, the character runs and when the key is released, the character stops running and continues walking. Very similar to the Super Mario logic for the big jump!! :).

Now let’s implement the ToggleRunState method. Add the method’s declaration to the .h file:


/**
* Gets call when the engine detects the Run entry
* Change to the character run state.
*/
void ToggleRunState();

Go to the .cpp and add the following lines to the implementation:


/**
* Gets call when the engine detects the Run entry
* Change to the character run state.
*/
void AHeroCharacter::ToggleRunState()
{
//If the CharacterMovement's MaxWalkSpeed attribute is 400.f we increase it to 900.f to achieve that the character will  move faster.
//Otherwise we set it to 400 again so the character move in the walk speed range.
    if(CharacterMovement->MaxWalkSpeed == 400.0f)
        CharacterMovement->MaxWalkSpeed = 900.0f;
    else
        CharacterMovement->MaxWalkSpeed = 400.0f;
}

By default, the movement speed value is 400. When the shift key is pressed, we change the MaxWalkSpeed to 900, which causes the character to move faster. When the shift key is then released, the method is called again and we set the value back to 400, decreasing the movement speed.

If you want to test your knowledge, you can implement the run mechanism in the HeroCharacter’s Blueprint. If you accept thus challenge, remember first to delete the C++ code. It should looks like this:

Blueprint version of the run mechanism

Blueprint version of the run mechanism

 

I personally prefer to keep all the character’s logic in code, but this exercise may serve as practice to increase your skills in the Blueprint Editor, something that’s new for much of us and I’m sure caught your attention :). I also recommend to expose the max and min values of the MaxWalkSpeed so it can be modifiable from the Editor and to avoid going to the code to change its values. Remember, in order to make variable values modifiable via the editor, you have to use the UPROPERTY macro, but this time I won’t show you how I did it so you must check how we did it previously and use your imagination. I’m sure you can do it 😉

Build and play the game. Let’s try it out. While you’re walking, press the shift key and you will see how the character moves much faster. We’re not quite finished yet because the character still uses the walk animation while running so it looks weird.

Adding the run animation to the character

Let’s add another animation to our character – the run animation. We will use the Idle/Walk state created previously to add the run animation. We will also use the same node to blend between the animations. An amazing feature of this type of node is that we can add more than two animations. The idea is to modify it to set three control points: the first one at the start of the graph will use Idle animation, the second in the middle of the graph will use the Walk animation, and the third at the end of the graph for the Run animation.

Import Run.FBX from your resources, open the IdleWalkBlendSpace1D created in the last tutorial, change the X Axis Range property to 900 (the movement value of the character when it’s running), and click the Apply Parameter Changes. Now add the Idle animation at the start, the Walk animation in the middle, and the Run animation at the end. Make sure the Enable Preview BlendSpace option is checked and move the cursor over the graph to see the blend between the animations according to the speed value. Pretty cool and easy, ehhh???

New IdleWalkBlendSpace1D configuration for the Idle/Walk/Run state

New IdleWalkBlendSpace1D configuration for the Idle/Walk/Run state

 

Save, play the game and try to run. Now our character walks and runs perfectly.

Running character pressing the D+Shift keys

Running character pressing the D+Shift keys

 

Adding coins in the scene for the character collect.

We already have our character walking, running and jumping through the scene in a side-scroller style, but we need to add some purpose to the game because wandering around isn’t much fun. Let’s try to improve it a little by adding some coins in the scene for the character to collect, a common feature in this style of game. In next tutorials, we will see what our character wins with these coins.

First, we need a coin model. I’m sure you can find several StaticMesh that you can use as coins from the MarketPlace. I strongly recommend you take some time to visit the MarketPlace. I’m sure that you will find a lot of things that you will love and many of them are FREE!! :D.

Anyway, you can download the FBX of a very simple coin here :S Its not amazing but it works for this tutorial. Import the FBX file to the project (I created a Coin folder). In the importing window, you will notice that Unreal detects that this is a StaticMesh. Expand the advanced options and select the materials and texture options. This way, we’re also importing the model’s material. That is also extremely simple.

Now with the resource imported, let’s create the C++ class that encapsulates all the coin logic. Create a new class in the Editor and named it Coin. This class will inherit from Actor. Select Yes when the Editor asks you if you want to open the class in the IDE. Modify the .h file so it looks like the following:


/** Represents a coins. The character can collect them by colliding with them. */
UCLASS()
class ACoin : public AActor
{
GENERATED_UCLASS_BODY()
   
    /**
     * USphereComponent is sphere shape component generally used to detect simple collisions
     * This will be the root component of the coin and with it we will detect the collisions between the character and the coins.
     */
     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
    TSubobjectPtr<USphereComponent> BaseCollisionComponent;
   
    /** Coin's StaticMesh, we used previously in the Character. We store the coin's StaticMesh instance. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
    TSubobjectPtr<UStaticMeshComponent> CoinMesh;
   
    /**  Boolean variable to enable/disable the coin */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Coin)
    bool bIsActive;
};

I recommend you pay attention to the code comments because I always point out which function has every line. Basically, we define the BaseCollisionComponent attribute to be the root component of our coin which we will use to detect collision. The other attribute is the UStaticMeshComponent which is used to define the StaticMesh that represents the coin in the level. The last one is the bIsActive we will used as a flag to disable the coin when the user collides with it.

Go to the .cpp file and modify the constructor to match the following code:


ACoin::ACoin(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
    //Create the USphereComponent instance.
    BaseCollisionComponent = PCIP.CreateDefaultSubobject<USphereComponent>(this, TEXT("BaseSphereComponent"));
   
    //Initialize the Actor's RootComponent with the USphereComponent.
    RootComponent = BaseCollisionComponent;
   
    //Create the UStaticMeshComponent instance
    CoinMesh = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("CoinMesh"));
   
    //We add the UStaticMeshComponent as child of the root component
    CoinMesh->AttachTo(RootComponent);
   
    //By default the coin will be active
    bIsActive = true;
}

We instantiate the USphereComponent as the coin’s root component. We also create the UStaticMeshComponent instance. We will soon configure it from the Editor and then added it to the RootComponent. Finally, we set the bIsActive variable to true because we want the coin to be active when it’s created.

Adding coins to the scene

Let’s create the Coin’s Blueprint as we did with the Character in the last tutorial. In the ContentBrowser, select the Coin folder, then right click and select the Blueprint option. Finally, set Coin as the base class and name it CoinBlueprint. As you will see, it contains the same components that we define in the USphereComponent constructor, for instance, the RootComponent and the UStaticMeshComponent. Unfold the CoinMesh and select the StaticMesh imported for the coin.

CoinBlueprint component's section. Adding the StaticMesh component

CoinBlueprint component’s section. Adding the StaticMesh component.

 

Now we will add some coins to the scene. Find the CoinBlueprint in the ContentBrowser and drag it into the level at the position where you want to place a coin. This must be a place reachable by the character. It’s important to remember that in this style of game, the character is placed on a fixed Y axis, so you must place the coins at the same Y value as the character in order for him to collide with the coins.

This is the simple level I made:

Level in edition mode with coins added.

Level in edition mode with coins added.

 

We added the coins to the level, but so far they don’t do anything. If you walk into the coins, nothing happens. Besides, the coins look very bad because they’re static. Let’s add some life to them.

Collision mechanism to collect the coins

At the moment, the character hits the coins but there isn’t any feedback. Let’s add the collision detection that, as its name suggests, will detect the collision between the character and the coins. We will have a “Collected coins” variable that we will increase when the character collides with a coin. We will create and call the OnCollected() method in the Coin class where we will disable the coin, delete it from the scene and print a log on the screen to debug the algorithm.

Open the HeroCharacter.h and add the following declarations:


    /** Character's amount of coins collected */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Coins)
    int32 CoinsCollected;

    /** It's called constantly in the character's Tick to check if its colliding with a coin */
    void CollectCoins();
   
    /**
     * Gets executed automatically by the engine every frame
     * @param DeltaSeconds the difference in seconds between the last and current frame.
     */
    virtual void Tick(float DeltaSeconds) OVERRIDE;

Before we get deep in code, let’s theorise on the functionality that we will use. Every Actor in UE4 implement the Tick method. This method is called automatically by the engine every frame. If you are reading this tutorial, you are probably familiar with game development, at least with its theory. If so, you will know this method’s significance. Basically, all of the Actor’s algorithms that must run constantly will be called inside this method. The method receives a float as a parameter. This is the amount of time, in seconds, that has passed since the last tick/frame. This value is commonly used in a variety of tasks. For instance, it can be used as a multiplier when modifying the character’s position or rotation in order to achieve an execution depending on the framerate as to avoid gaps in case that the framerate decreases.

So we will call the CollectCoins method in the Tick method so it runs constantly. Internally, this method checks if a coin is inside the Character’s CapsuleComponent. If it is, that means that the character is colliding with that coin do we should trigger our collision mechanism.

Open the HeroCharacter.cpp file. At the end of the constructor implementation, add the CoinsCollected = 0 line. This causes the CoinsCollected variable to be set to zero when the character is create and is done because hasn’t collected any coins. Add the CollectCoins and Tick methods:


/** It's called constantly in the character's Tick method to check if is colliding with a coin */
void AHeroCharacter::CollectCoins()
{
    //AActors array to save temporary all the actors that are colliding with the character
TArray<AActor*> CollectedActors;
   
    //GetOverlappingActors method of the CapsuleComponent. This method returns all the actors colliding with the character in the array we pass as parameter.
    //All the objects that are currently inside the capsule.
    CapsuleComponent->GetOverlappingActors(CollectedActors);
   
    //We iterate through all the objects inside the CapsuleComponent.
    for(int32 i = 0; i < CollectedActors.Num(); i++)
    {
        //We have to cast the array elements to ACoin because the array is declared as AActors.
        ACoin *Coin = Cast<ACoin>(CollectedActors[i]);
       
        //We make sure that the coin is active and that the Destroy method hasn't been called
        if(Coin != NULL && !Coin->IsPendingKill() && Coin->bIsActive)
        {
            //We increase the coins collected amount.
            CoinsCollected++;
           
            //Finally, we call the OnCollected method of the Coin class to execute all the collect coin logic.
            Coin->OnCollected();
        }
    }
}

/**
* Gets executed automatically by the engine every frame
* @param DeltaSeconds the difference in seconds between the last and the current frame.
*/
void AHeroCharacter::Tick(float DeltaSeconds)
{
    Super::Tick(DeltaSeconds);

    //In every update is called the CollectCoin to constantly check if it's colliding with a coin.
    CollectCoins();
}

Take a minute to read every line’s comments to really understand the collision detection process. This is a very simple collision detection but it’s enough to understand how to work with it in UE4 :). It’s important to clarify that inside the CollectCoins method we have a reference to the ACoin class created by us. To avoid errors, we have to add #include “Coin.h” declaration at the top of the .cpp file below the #include “UE4Demo.h” line.

Only one small thing is left. If you try to build now you will get an error because when a collision is detected, the OnCollected method of the Coin class is called and we haven’t implemented this method yet. Let’s do that now:

Add the method’s declaration to the .h file and the implementation in the .cpp.


/** It's called when a collision is detected */
void ACoin::OnCollected()
{
    //To Debug we print a log on the screen
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin Collected !!");
   
    //We change to false the bIsActive flag
    bIsActive = false;
   
    //We call the Actor's Destroy method, to remove the coin from the scene
    Destroy();
}

This method will be called when a collision is detected. First we use the AddActorLocalRotation method of the framework’s GEngine object. This method is very handy because it allows us to print messages in a specific colour at a certain amount of time on the screen. To debug our code in runtime is very useful. Here we print Coin Collected when the character collides with a coin. Besides that, we set the bIsActive variable as false and we remove the coin from the scene using the Actor’s Destroy method.

Build and run the game one more time. Now walk into a coin … Very nice!! When the character passes through a coin, the coin is removed from the scene. Internally, the amount of coins collected is increased (at the moment there isn’t any visual feedback regarding this value) and then we print the temporary Coin Collected¡! log to the screen.

“Debugging” the scene collisions

If you are good at paying attention to small details, I’m sure you will notice a small problem with this collision mechanism. Try to reach a coin slowly, you will notice that the collision occur before the character actually touches the coin. To find the problem, UE4 provides us with an amazing command that allows us to check the collision component of an actor at runtime. Run the game one more time and pay attention in the upper-right corner of the Editor. You’ll notice there is a text field that allows us to write commands. Write in the field: show COLLISION and press the Enter key. Immediately, the collision component appears over every actor .

Run time game with the show COLLISION command active to debug the Actor's collision component.

Run time game with the ‘show COLLISION’ command active to debug the Actor’s collision component.

 

Notice two things that could the cause the problem. First, the coin component is bigger than the coin itself. Second, the character’s capsule radius could be reduced. End the game execution and open the CoinBlueprint then select ROOT in the components mode. In the Details panel, search for the Shape section that holds the sphere radius. Change its value to 15 and check out the preview showing how the sphere surrounds the coin. Notice how this adjustment better fits the model. Save and try again. You will see how the collision detection has improved as now the character has to be very close to catch the coin.

Modifying the sphere component radius to adjust the collision detection

Modifying the sphere component radius to adjust the collision detection

 

You can do the same with the character’s capsule if you want to continue improving the collision mechanism. It’s important to mention that this value can be defined in the class constructor by code. Try to do it by yourself to practice.

Rotating coins on its own axis.

To add some life to the coins, we will rotate them on their own Y axis. Close the editor, open the Coin.h class and add the following lines:


    /** Coin rotation factor */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rotation")
    FRotator RotationRate;
   
    virtual void Tick(float DeltaTime) OVERRIDE;

We simply add the Tick method and a new RotationRate attribute of FRotator type. This is the rotation vector we will use to rotate the coin in every Tick call. Actually, there is no need to declare an attribute but in doing so, we gain the opportunity to configure the rotation factor in the editor, thanks to the UPROPERTY macro.

Go to Coin.cpp file. At the end of the constructor, add this two lines:


    //Initialize the coin rotation factor in each update
    RotationRate = FRotator(0.0f, 180.0f, 0.0f);
   
    //Enable the Tick method of this Actor
    PrimaryActorTick.bCanEverTick = true;

The first line is the rotation vector’s initialization. By default, the Tick method isn’t called automatically in an Actor inherited class such as our Coin class. To enable the call to the Tick method in this class, it’s necessary to set the PrimaryActorTick.bCanEverTick attribute as true.

Very well, now add the Tick method’s implementation:


void ACoin::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    //Adds a rotation factor to the coin in each Tick call
    AddActorLocalRotation(this->RotationRate * DeltaTime, false);
}

The code is very simple. Basically we add a rotation factor thanks to the AddActorLocalRotation, in each update.

Ready!! Build, run and test. Super nice, right!! The coins are constantly rotating in the scene, waiting to be caught :).

Implementing the coin logic in the Blueprint.

As I already mentioned in the last tutorial, the decision of whether to use the code or the Editor is up to the individual. I personally follow these two rules of thumb. 1. Implement all the related things only in one place (for maintenance purpose). In other words, don’t have half of the logic in code and the other half in the Blueprint. 2. If the Actor logic is very simple like it is for this coin, the ideal solution is to use the Blueprint. However, when the thing needed to be implemented is large and complex, I personally prefer to use C++.

You could have some practice implementing the coin logic in the Blueprint. Do you dare? It should look something like:

Coin VisualScript

Coin VisualScript

 

Notice that we implement what happens when the OnCollected method is called in the Blueprint. We still have to add in the method’s declaration, the UFUNCTION(BlueprintNativeEvent) macro, or the UFUNCTION(BlueprintImplementableEvent). Next I will explain both:

UFUNCTION(BlueprintImplementableEvent) is designed to be overridden by a blueprint. Do not provide a body for this function; the automatically generated code will include a thunk that calls ProcessEvent to execute the overridden body.

[UFUNCTION(BlueprintNativeEvent) macro]. This function is designed to be overridden by a blueprint, but also has a native implementation. Provide a body named [FunctionName]_Implementation instead of [FunctionName]; the automatically generated code will include a thunk that calls the implementation method when necessary.

For example, if you want to test the OnCollected method, the definition will be like this:


UFUNCTION(BlueprintNativeEvent)
void OnCollected();

And the implementation should look like:


void ACoin::OnCollected_Implementation()
{
    //As Debug we print a log on the screen
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin Collected !!");
   
    //We change the bIsActive flag to false
    bIsActive = false;
   
    //We remove the coin from the scene with the Destroy method
    Destroy();
}

The silver lining is that we can have our code implementation, but we can also override this implementation in the Blueprint … cool, right? UE4 stuffs!! :). Try the coin logic implemented in VisualScript in order to gain confidence in the Blueprint Editor, one of the wonders of UE4.

Conclusion

Well, I think it’s time to call it a day. In this second tutorial, we did several new things. Among them, we made a simple collision detection mechanism We implemented the Tick method. We added the run and jump animations to the character. We configured our game camera to the 3D Side-Scroller style. We saw some variables and macro class functions for the integration between the code and the Blueprint Editor, etc.

In next tutorial, we will continue to build our game. We will add a HUD so the user knows the number of coins collected, and the time available to achieve some goal. We will define the GameMode, the win and lose conditions and so much more ;).

I hope you found this tutorial useful. If you did, please leave me your comments and share this tutorial with the rest of your friends who are also passionate about game development with UE4. Till next time!!… Bye.

Introducción al desarrollo de video juegos con Unreal Engine 4

Unreal Engine 4, en mi opinión, es uno de los motores de juegos más potente que existe en la actualidad, y el equipo de Epic Games lo ha puesto por completo a disposición de todos bajo una licencia 19 USD mensuales.

Este primer tutorial pretende dar una introducción al UE4. Crearemos la base de nuestro juego, donde tendrás al personaje protagónico caminando por el nivel usando una cámara fija, con controles básicos. Este simple inicio nos permitirá aprender a importar los modelos 3D al proyecto. Crear la clase necesaria para controlar al personaje. Entender la filosofía que sigue el framework de Unreal en su modelo de clases. Una introducción a la programación en Unreal Engine usando C++. La comunicación entre C++ y el Editor. Los mecanismos de animación del personaje y una introducción al Visual Scripting usando el Blueprint Editor.

Obteniendo el Unreal Engine 4

El proceso para obtener el motor es súper simple. Entra en https://www.unrealengine.com/register regístrate y paga los primeros 19 USD, créeme, probablemente estos sean los 19 USD que más alegría te darán en la vida :). Ahora tendrás acceso a lo mismo con lo que trabaja el equipo de Epic Games.

El próximo 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 versión o compilando todo el código fuente … sip, así mismo, por si fuera poco, tenemos acceso ha todo el código 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 algún problema con el proceso puedes dejarme tus comentarios.

Requisitos antes de comenzar

Es válido aclarar en este momento que este y los próximos tutoriales asumen que tienes un dominio AVANZADO de C++ y del desarrollo de juegos.

Modelo 3D del personaje protagónico 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 diseñadores y animadores de nuestro equipo, con herramientas de modelado y animación 3D como Maya, 3DsMax o Blender. Al terminar el proceso de modelación y animación en estas herramientas, se exporta el modelo, el esqueleto y las animaciones en formato FBX.

Como en lo personal, el modelado y la animación 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 daría nuestro equipo de diseño. 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 algún 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 esqueleto.

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

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 información 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 súper simple. Abrimos el editor y nos muestra una ventana con dos pestañas: Project, que contiene los proyectos existentes previamente creados y New Project, que como es lógico, 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, según el estilo que queramos crear. 3ra Persona, 1ra Persona, Top-Down o Side-Scroller.

Como el objetivo que tiene este primer tutorial, es una introducción al UE4, no vamos a usar ninguna de estas plantillas relativamente avanzadas, vamos a crear nuestro proyecto prácticamente 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

Ventana para Crear o Abrir un proyecto en Unreal Engine 4

Hecho esto se crea automáticamente el proyecto y se abre en el IDE correspondiente según 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 programación 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 después Menú Product/Build For/Running.

El proceso de compilación demorará unos segundos. Una vez que termina podemos seleccionar desde el menú del XCode, Product/Run. Esto nos abrirá automáticamente el Editor con nuestro proyecto.

Unreal Engine 4 Editor con nuestro nuevo proyecto acabado de abrir

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 botón Play de la barra Superior (Toolbar) para ver lo que tenemos. Por defecto tendremos el control de la cámara 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 diseño nos entregó el modelo exportado en FBX con su esqueleto y su dos animaciones básicas :), 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 Botón 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 más 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 automáticamente seleccionado Skeletal Mesh.

Ventana FBX Import del Unreal Engine 4

Ventana FBX Import del Unreal Engine 4

Vamos a tomarnos unos minutos para un poco de teoría. 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 estático de nuestro juego, por ejemplo una silla, un edificio. O sea, solamente el modelo 3D sin animación, 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 serían Skeletal Mesh.

Animation: Un Animation, es la información 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 más adelante.

Automáticamente UE4 detecta que lo que estamos importando es un Skeletal Mesh no es necesario cambiar más nada, los parámetros por defecto son suficiente, da clic en el botón Import. En caso de algún warning en el proceso de importación, ignóralo. En próximos 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 animación en UE4.

El Skeletal Mesh de nuestro héroe en el Persona Editor

El Skeletal Mesh de nuestro héroe 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 ningún 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 automáticamente al importar el Skeletal Mesh, este asset de momento no lo usaremos, en próximos 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 botón que dice Simulate, da clic en él y mira lo que pasa. Eso te dará una noción del objetivo de este recurso generado automáticamente al importar el Skeletal Mesh.

Por último el Hero_Skeleton es solamente el esqueleto del modelo que importamos, pero el esqueleto por separado. Una característica 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 código :)

Introducción a la programación en Unreal Engine 4

Un proyecto en Unreal Engine 4 está compuesto básicamente de dos grandes piezas que trabajan en conjunto. Los niveles, que es lo que se trabaja en el Editor y el proyecto de programación, que trabajamos en el IDE de programación. Vimos como al crear un nuevo proyecto en UE4 se crean ambas partes. Ahora vamos a trabajar en la segunda parte, la parte del código.

En Unreal Engine 4 se programa en C++, al crear un nuevo proyecto, automáticamente se crea un proyecto en el XCode (o Visual Studio si usas Windows) con las clases básicas para nuestro juego. Abre tu IDE de programación con el proyecto creado. Dentro de la carpeta Source es que se encuentran los fuentes nuestros. Dentro de la carpeta Engine están todos el framework. Tener acceso a esto es genial, porque sirve de mucha ayuda para revisar como están 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 rápidamente la filosofía 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 estáticos, 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. Básicamente 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 dominarás esta filosofía, la jerarquía de clases y la relación entre ellas.

Volviendo al código, 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, además es la encargada de definir el PlayerController, el Pawn por defecto, entre otras muchas cosas. Es el núcleo del juego. Si abrimos el .h veremos que es una clase que hereda de AGameMode y de momento no tiene más nada.

//AUE4DemoGameMode.h
#pragma once

#include "GameFramework/GameMode.h"
#include "UE4DemoGameMode.generated.h"

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

Como notarás de seguro, la clase tiene en su declaración dos macros que te llamarán la atención, 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, Serialización, Inicialización automática de las propiedades, Integración automática con el Editor etc”.

Ahora vamos a ver la implementación de nuestro GameMode. Como verás en el UE4DemoGameMode.cpp tendrás solamente la implementación del constructor.

//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 inicialización 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 estática 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 implementación del PlayerController de nuestro juego y como verás está vacía, 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 algún comportamiento personalizado.

Bien, basta de teoría, 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 protagónico de nuestro juego tiene que heredar de Character.

Para agregar una nueva clase al proyecto la forma más cómoda 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 pequeña descripción de las mismas. Selecciona Character, da en el botón 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 protagónico de nuestro juego, este es un buen punto para comentar una de las cosas que en lo personal más trabajo me costó adaptarme al entrar en el mundo de Unreal Engine, sobre todo porque llegué a Unreal Engine después de trabajar mucho en el desarrollo de juegos 2D con motores como el Cocos2D. En este caso todo se hace desde código (aunque ya a estas alturas han varios Editores geniales para Cocos2D). En UE4 la filosofía de trabajo es muy distinta, aquí por supuesto que podemos hacerlo todo desde programación pero esto implica que el ritmo de producción generalmente será más lento y propenso a bug. Por este motivo al desarrollar juegos sobre Unreal Engine trabajaremos indistintamente con el Editor o directamente desde el código. Básicamente es decisión de los desarrolladores cuando usar uno u otro.

Para demostrar el engranaje entre el código en C++ y el Editor en Unreal Engine vamos a configurar nuestro Character en los dos lados, esto también nos permitirá demostrar lo genial que quedan comunicados el código C++ y el Editor.

Bien, ya tenemos desde código 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 botón Blueprints. Selecciona Blueprints/New Class Blueprint en la parte de abajo de la ventana hay una sección 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.

imagen_06

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 máximo de velocidad que toma el personaje al desplazarse, hay muchísimas más 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 detección de colisiones con el personaje. Es esa capsula transparente que se ve en el Viewport del Editor y es la zona de colisión del personaje.

Por último dentro del CapsuleComponent tenemos un Mesh, que como ya te imaginarás es el Mesh que representa a nuestro personaje. Además hay un ArrowComponent que nos ayuda para saber la dirección 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 sección 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 héroe. Al hacer esto en el Viewport se verá el modelo de nuestro héroe. Usa las herramientas de traslación y rotación para colocar el Mesh dentro del CapsuleComponent y mirando en la misma dirección que el Arrow Component. Por último da clic en el botón Save en la esquina superior derecha del Editor.

Mesh del personaje en la posición correcta en el HeroCharacterBlueprint

Mesh del personaje en la posición 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 notarás no hay ningún 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, asegúrate que tienes configurado bien el GameMode. Da clic en el botón World Settings del Toolbar y asegúrate tener seleccionado en la sección GameMode nuestra clase U4DemoGameMode, debajo de GameMode tendrás 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 notarás 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 código para demostrar nuevamente la comunicación entre los componentes del Editor y el código en C++. Cierra el Editor abre el proyecto C++ y busca la clase UE4DemoGameMode modifica la implementación del constructor para que quede de la siguiente forma.

AUE4DemoGameMode::AUE4DemoGameMode(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	PlayerControllerClass = AUE4DemoPlayerController::StaticClass();
    
    //Obtiene en PlayerPawnBPClass.Object la referencia al HeroCharacterBlueprint creado y configurado desde el Editor
	static ConstructorHelpers::FObjectFinder<UClass> PlayerPawnBPClass(TEXT("Class'/Game/Character/HeroCharacterBlueprint.HeroCharacterBlueprint_C'"));
    
    //Inicializa el atributo DefaultPawnClass con el HeroCharacterBlueprint creado y configurado desde el editor
	if (PlayerPawnBPClass.Object != NULL)
	{
		DefaultPawnClass = PlayerPawnBPClass.Object;
	}
}

Vamos a dar un stop aquí para explicar que acabamos de hacer con estas pocas líneas porque aunque tengas experiencia en C++ de seguro que esta sintaxis te parecerá algo rara. En la primera línea 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 dirección 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 implementación 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 declaración 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, básicamente todos los strings que escribamos directo en el código 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 teoría 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 automáticamente 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 automáticamente busca en el Level si hay una instancia de un Player Start y agrega en esa posición el Character.

Pero que problema tenemos ahora, perdimos el control, ya no podemos desplazarnos por la escena y la cámara está como en los ojos del personaje :(. Bien, vamos a solucionar este asunto configurando temporalmente una cámara estática en nuestro juego.

Configurando una cámara estática desde C++

En el Editor da clic derecho dentro del ViewPort y selecciona del menú desplegable Place Actor/Camera. Usa las herramientas de traslación y transformación para apuntar la cámara en la dirección del Play Start, para que se vea el personaje. Así me quedó a mi:

imagen_08

Ahora vamos a decirle al Unreal que la vista del juego será desde esta cámara. Para esto tenemos que comentar algo de teoría.

Como hablamos anteriormente según la filosofía de Unreal es el PlayerController la interfaz entre el personaje protagónico del juego (el Character) y el ser humano. Por lo que es lógico que lo referente a la vista del juego sea implementado aquí. PlayerController tiene el método SetViewTargetWithBlend este método permite definir en cualquier momento a donde es que está “mirando” la cámara del juego. Lo que vamos a hacer es llamar a este método y decirle que use la cámara que pusimos en el Level como la cámara del juego.

Podemos cambiar la dirección a la que apunta la cámara de nuestro juego en cualquier momento, pero en este caso queremos que desde el inicio sea la dirección a la que apunta la cámara 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 método que se llama, como dice su nombre, cuando inicia el juego. Vamos a sobrescribir este método en nuestro PlayerController (que deriva de AActor) para en ese momento cambiar la cámara del juego.

Abre UE4DemoPlayerController.h y abajo del macro GENERATED_UCLASS_BODY() agrega la siguiente línea: virtual void BeginPlay() override; con esto hacemos visible el método BeginPlay en nuestra clase UE4DemoPlayerController para poderlo sobrescribir en el .cpp.

Abre ahora UE4DemoPlayerController.cpp y agrega el siguiente método debajo del contructor. Revisa con detenimiento los comentarios para que entiendas lo que se hace dentro del método.

/** Metodo heredado de la clase AActor se llama automaticamente por el motor cuando comienza el juego. */
void AUE4DemoPlayerController::BeginPlay()
{
    //Llamamos el Begin Play de la clase padre
    Super::BeginPlay();
    
    //Recorremos todos los Actores en el Level mediante el TActorIterator
    //TActorIterator es un iterator parametrizado que nos permite recorrer todos los actores en el level
    for (TActorIterator<ACameraActor> It(GetWorld()); It; ++It)
    {
        //Obtenemos el actor actualmente en el loop. Como solo tenemos un solo ACameraActor en el Level, el iterator solo iterará una vez
        ACameraActor* _mainCamera = *It;
        
        //Configuramos el nuevo punto de vista del juego con la camara.
        //SetViewTargetWithBlend puede recibir más parametros, pero tienen valores por defecto, y de momento no necesitamos modificarlos.
        this->SetViewTargetWithBlend(_mainCamera);
    }
}

Listo !! compila y corre. Ahora verás el juego usando la cámara que agregamos al Level y ya podrás ver nuestro Character agregado a la escena.

Configurando una cámara estática mediante el Blueprint Editor

Bien, quisiera hacer un paréntesis aquí para volver a tocar el tema del Blueprint Editor. Al comenzar en Unreal Engine muchos chocamos con la incógnita: Cómo hago esto? Mediante C+ o mediante el Blueprint. Al final la decisión es de cada cual y a medida que vayas cogiendo soltura en Unreal Engine sabrás 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 cámara del juego, pero ahora sin escribir una línea de código, todo lo haremos mediante el Blueprint Editor.

En el Editor da clic en el botón 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 lógica 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 básicamente es programar pero con gráficos (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 podrás hacer en el Blueprint Editor.

Comenzaremos agregando el Evento Begin Play. Clic derecho en el centro de la pantalla desmarca la opción Context Sensitive y busca Event Begin Play. Acabamos de agregar a nuestro script visual un Nodo que representa al método Begin Play de nuestro juego. Ahora, según nuestra implementación en C++ lo que hicimos dentro del BeginPlay fue obtener la referencia de la cámara que tenemos en el Level y llamar al método de la clase PlayerController SetViewTargetWithBlend pasándole como parámetro la cámara. Pues eso mismo haremos aquí.

Primero, necesitamos una referencia al PlayerController, recuerda que este script es “global” a nivel del Level y la implementación 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 método 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 suéltalo. Con esto hemos hecho la conexión 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 método Set View target with Blend. Pero que pasa, SetViewtargetWithBlend vimos que es un método 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 estarás diciendo que el método SetViewTargetWithBlend que se llamará es el del PlayerController retornado por el Nodo Get Player Controller. Por último recuerda que hay que pasarle como parámetro 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 cámara. Salva estos cambios, cierra el Editor y selecciona en el Level la cámara que agregamos anteriormente. Ahora abre de nuevo el Editor da clic derecho y verás 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 botón que dice Compile. Da clic ahí. Por último vamos a eliminar la sobre-escritura del método Begin Play en la clase C++ ya no es necesario (si quieres coméntalo para que no pierdas el código).

Cierra el Editor, abre el proyecto C++ y comenta en el UE4DemoPlayerController.h la declaración del método BeginPlay. Ve ahora al UE4DemoPlayerController.cpp y comenta o elimina completamente la implementación del método BeginPlay.

Listo !!. Compila y ejecuta el juego. Como notarás, es idéntico el resultado :). Ya te digo, es decisión tuya implementar lo que quieras en el Blueprint Editor o en C++ tu mismo le iras encontrando las ventajas y desventajas a cada método según lo que quieras hacer.

Tomate unos minutos si quieres, que aún 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 protagónico, ya visto desde una cámara fija pero está ahí quieto sin hacer nada y estático totalmente. Vamos a darle un poco de vida.

Recuerda que nuestro equipo de diseño :) nos entregó además del modelo con su esqueleto en FBX las animaciones de caminar y reposo, también 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 verás que por defecto en la ventana de FBX Import sale seleccionado Animations. Más abajo tiene la opción que permite ya en el momento de la importación seleccionar el esqueleto al que están 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 animación, reproducirla y muchas más cosas que veremos en próximos tutoriales.

Ya tenemos las animaciones ahora falta asociarlas con nuestro personaje.

Creando la maquina de estado y actualizando el Character con la animación de reposo y caminar mediante Animation Blueprints.

El Animation Blueprints es la herramienta que nos da Unreal Engine para implementar toda la lógica de las animaciones del personaje de una forma súper simple. A partir de máquinas 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 vacío y selecciona Animation/Animation Blueprint. Esto te abrirá la ventana de creación de Animation Blueprint. En la sección Parent Class selecciona AnimInstance y abajo en la sección Target Skeleton escribe el nombre del esqueleto que usa nuestro héroe, Hero_Skeleton por último da clic en el botón OK.

Automáticamente 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 verás que hay una sección 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.

imagen_09

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 teoría.

En Unreal Engine hay un mecanismo súper genial e intuitivo para definir las animaciones que tienen los personajes según su estado y las condiciones que definen cada estado. O sea, si el personaje está en reposo se animará la animación de reposo, si el personaje está caminando se ejecutará la animación de caminando. Se pueden hacer ligamentos entre animaciones, para que estos cambios sean mas fluidos, además 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. Cámbiale el nombre a algo lógico, 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 lógica del estado Idle. Dale doble clic al nodo Idle, da clic derecho y selecciona Animation/Play Idle. Esto agrega el Nodo que representa la animación 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 animación del Idle

imagen_10.1

imagen_10.2

imagen_10.3

Ejecuta el juego. Ya tenemos a nuestro personaje en su estado de reposo y animándose perfectamente.

Personaje principal ya en el juego en estado de reposo animándose correctamente.

Personaje principal ya en el juego en estado de reposo animándose correctamente.

Configurando los controles del juego

Muy bien, hasta ahora hemos creado y configurado el Character, hemos configurado una cámara fija temporal para el juego y hemos configurado la primera animación del personaje, el próximo 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, Sección Engine/Input, Bloque Bindings. Da clic en el botón 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 sección 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.

imagen_12

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 programación y lo que seleccionamos en el combobox es el control que disparará esta acción. El valor de Scale es un valor numérico que llega al método desde programación, generalmente con -1 y 1 es suficiente para la mayoría de los casos. Otra cosa a notar es que gracias a este valor de Scale las acciones que son en una dirección 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 atrás.

Bien, hecho esto vamos a programar en el Character la lógica 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. Básicamente necesitamos dos cosas. Sobrescribir el método virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) de APawn para registrar los métodos 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 modifícala para que quede de la siguiente forma:


UCLASS()
class AHeroCharacter : public ACharacter
{
	GENERATED_UCLASS_BODY()
    
protected:
    
    /** 
     * Se llama cuando el motor detecta la entrada configurada para 'MoveForward'.
     * En este caso cuando el usuario toca la tecla W o S del teclado 
     */
	void MoveForward(float Value);
    
    /**
     * 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);
    
    /**
     * 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;
    
};

Nada raro aquí, simplemente definimos dos métodos en donde vamos a implementar la lógica para cuando se detecte cada entrada y agregamos aquí también la declaración del método SetupPlayerInputComponent de APawn para poderlo sobrescribirlo

Ahora pasa al HeroCharacter.cpp y modifícalo para que quede de la siguiente forma:


#include "UE4Demo.h"
#include "HeroCharacter.h"


AHeroCharacter::AHeroCharacter(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{

}

void AHeroCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    //Le dice al motor que cuando detecte las entrada de tipo MoveForward que llame al metodo AHeroCharacter::MoveForward
	InputComponent->BindAxis("MoveForward", this, &AHeroCharacter::MoveForward);
    
    //Le dice al motor que cuando detecte las entrada de tipo MoveRight que llame al metodo AHeroCharacter::MoveRight
	InputComponent->BindAxis("MoveRight", this, &AHeroCharacter::MoveRight);
}


/**
 *  Se llama cuando se detecta la entrada de tipo MoveForward (Cuando el usuario toca las teclas W o S).
 *  Determina la dirección en la que está el personaje y le aplica un movimiento (positivo o negativo) en esa dirección
 *
 *  @param Value 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))
	{
		//Obtiene la rotacion actual
		const FRotator Rotation = Controller->GetControlRotation();
        
		// Crea el vector de direccion a partir de hacia donde está rotado 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 (Cuando el usuario toca las teclas 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)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		//Determina la dirección del movimiento hacia los lados. Notar que solo nos intereza la rotacion en el eje Y
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
        
		// Crea el vector de la dirección y aplica el movimiento
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		AddMovementInput(Direction, Value);
	}
}

Ya aquí si tenemos algunas cosas que comentar, pero de seguro a estas alturas tienes una idea de todo. Primero, en SetupPlayerInputComponent usamos el parámetro que recibe para configurar los métodos 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 método MoveForward. Y el mismo principio para la otra entrada.

Ahora vamos a ver la implementación del método MoveForward. Este método recibe un parámetro float, que es el valor Scale que registramos en el Editor. O sea, cuando se toque la W se llamará este método con 1.0 como parámetro y cuando se toque la S se llamará este método con -1.0 como Value.

El método lo que hace es determinar la rotación que tiene el modelo y el vector en la dirección a la que está orientado y mediante el método AddMovementInput hacemos que el personaje se mueva en esa dirección. Fíjate que se calcula la dirección y como se pasa Value que será 1 o -1 entonces el personaje se moverá hacia delante o hacia atrás según Value. AddMovementInput es un método de APawn que permite aplicar un movimiento al Pawn para el caso del personaje que no sea un cuerpo físico, como el nuestro. Para el caso del MoveRight fíjate que es prácticamente lo mismo, pero al calcular la dirección 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 aún tenemos dos problemas con este movimiento. Primero, el personaje no rota en la dirección del movimiento como sería lo lógico, y el otro problema es que a pesar que se está moviendo sigue con su animación de reposo. Vamos entonces a solucionar estos dos problemas.

Primero, para solucionar el problema de la rotación es muy fácil. Abre el HeroCharacter.cpp y modifica el constructor para que te quede de la siguiente forma:

AHeroCharacter::AHeroCharacter(const class FPostConstructInitializeProperties& PCIP)
: 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 rotación del Controller.
    bUseControllerRotationYaw = false;
    
    //Configuración del componente CharacterMovement
    
    //Al estar en true habilita para que el character se rote en la dirección del movimiento al comenzar el movimiento.
	CharacterMovement->bOrientRotationToMovement = true;
    
    //Factor de rotación para la propiedad anterior.
	CharacterMovement->RotationRate = FRotator(0.0f, 540.0f, 0.0f);
    
    //Bajamos un poco el valor por defecto de MaxWalkSpeed para que el personaje camine un poco más lento.
    CharacterMovement->MaxWalkSpeed = 400.0f;
}

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 animación de caminando al personaje.

Vamos a trabajar ahora en el último problema que tenemos, hacer que el personaje cuando esté en reposo tenga su animación de reposo (como ahora) pero cuando esté caminando reproduzca la animación 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 harán blending según 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 animación y otra). En el rango pon 0 y 100. Ahora fíjate que más abajo tienes un espacio como de una gráfica, arrastra hacia ahí desde el panel Asset Browser la animación Idle y colócala al inicio del eje X, has lo mismo para la animación Walk y colócala al final del eje. Listo, ahora mueve el cursor sobre el eje y fíjate 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.

Configuración del IdleWalkBlendSpace1D

Configuración 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 manejarán 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 gráfico. Da clic aquí y dale el nombre de Speed a la variable, arrástrala 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.

imagen_14

Ya tenemos el Nodo Idle/Walk listo, pero te estarás 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 animación obtenga el Pawn (que sería nuestro personaje) después que se llame al método GetVelocity que retorna el vector de desplazamiento que lleva el personaje en ese momento. Este vector por supuesto se modifica gracias a la implementación 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 tendrás 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 programación directo. Pero por ejemplo, la lógica 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 animación del personaje en un solo lugar y poderlo repasar y pre visualizar fácilmente.

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 explicación 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 lógica para setear el valor de la variable Speed usada dentro del State Machine del personaje para cambiar entre las animaciones de caminando y reposo.

Algoritmo del HeroAnimBlueprint/EventGraph con la lógica 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 moviéndose por el terreno correctamente según queramos y cuando está detenido se anima con su animación de reposo y cuando está caminando se anima con su animación de Walk. :)

Conclusión

Hasta aquí este tutorial de introducción al Unreal Engine 4. En el próximo tutorial modificaremos la cámara, los controles y el movimiento del personaje para hacer nuestro juego un side-scroller style. Además agregaremos algo de lógica 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… déjame saber tus comentarios :).