Sistema de pasos en Unreal Engine y Wwise (Blueprints and C++)

If you prefer to read an English version, click on this button =>

Unreal Engine Version: 5.0.3

Wwise Version: 2021.1.10.7883

Este post the muestra cómo crear un sistema de pasos de audio en Unreal Engine 5 y Wwise. Este sistema usa un line trace generado desde la posición del Personaje hacia el piso. Este line trace va a obtener información sobre el Physical Material de las superficies y va a definir Ak Switch values en Wwise para cambiar el tipo de sonido de pasos.

Para este proyecto, he implementado este sistema dos veces, una usando el scripting visual Blueprints y otra usando C++ nativo. Aquí una lista con herramientas y palabras clave usadas en este proyecto:

Programé todo el sistema dentro de la clase padre C++ MyUE5ProjectCharacter, la clase blueprint hija BP_ThirdPersonCharacter, y el blueprint de animación ABP_Manny.

Importante:

Ten en consideración que esta guía no pretende enseñar diseño de sonido creativo. En cambio, se enfoca exclusivamente en aspectos de implementación y programación de game audio.


Descarga el Proyecto Aquí:

IMPORTANTE!

〰️

IMPORTANTE! 〰️

Prerequisitos:

  1. Crea un proyecto C++ third-person vacio y llámalo “MyUE5Project”.

  2. Descarga e integra el plugin Wwise en tu proyecto por medio del Wwise Launcher.

  3. Activa la opción de Event-Based Packaging.

Para que este tutorial tenga sentido, es importante que sepas cómo integrar el plugin Wwise en Unreal Engine. Adicionalmente, considera leer y consultar mi post anterior sobre UPROPERTY & UFUNCTION:

IMPORTANTE!

〰️

IMPORTANTE! 〰️

 

Setup Wwise:

Dentro del proyecto Wwise, crea un switch group llamado Footsteps en la pestaña Game Syncs . Añade cuatro switches, uno por cada tipo de paso.

 

Ve a la pestaña de Audio y crea un Switch Container llamado “Footsteps” con cuatro Random Containers dentro; uno por cada tipo de paso. Arrastra los archivos de audio apropiados dentro de estos containers. Define el switch group y el switch por defecto en el container. Arrastra y asigna los random containers a los switches correctos.

Da click derecho en el switch container “Footsteps”, y crea un nuevo evento llamado “Play_Footsteps”.

 

Como un paso adicional, puedes definir una modulación aleatoria de la afinación dando click derecho en Pitch > Enable Randomizer. Esta opción añade variación adicional a los sonidos de pasos. Repite este proceso por cada Random Container en el contenedor.

Guarda el proyecto.

 

Materials and Physical Materials:

Los Environmental Artists usan recursos de tipo Material y Physical Material para definir como se ven y simulan la física las superficies en el juego. Como artistas y programadores de audio, podemos usar estos materiales añadidos a las superficies y un Line trace para definir switches Wwise de forma dinámica.

Crea una carpeta de materiales y añade un Material y un Physical Material por cada superficie requerida. Para este proyecto, cree cuatro materiales diferentes.

 

Da double click en cada material y define su color y su Physical Material en el editor.

Ve a Window > Place Actors > Plane. Arrastra y coloca estas nuevas superficies en el viewport, y después asígnale un Material. Adicionalmente, puedes añadir un nombre a estas con un Text Render Component.

 

Setup C++:

Implementé todas las propiedades de este proyecto y un Ak Audio Component en C++. 

La clase blueprint va a heredar todas estas propiedades de la clase padre y las va a exponer en el graph blueprint. Finalmente, cree dos funciones en C++ y dos funciones en Blueprints que hacen lo mismo, para mostrarte cómo los dos sistemas se reflejan.

Importante:

Yo uso comentarios de tipo Doxygen para explicar el código. Estos comentarios no van a comprometer la funcionalidad del código o su compilación. Siéntete libre de copiar el código tal como está escrito aquí.

Build.cs:

Abre la solución en tu IDE y localiza MyUE5Project.Build.cs en MyUE5Project > Source, y añade "AkAudio" y "PhysicsCore" como dependencias del build.

/** Añade "AkAudio" y "PhysicsCore" para poder usar y compilar el API de Wwise y UPhysicalMaterial en C++ */
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "AkAudio", "PhysicsCore"});

Declaración de Funciones y Propiedades:

Ve a MyUE5Project > Source, y abre MyUE5ProjectCharacter.h Incluye estas directivas:

.h file:

#include "AkComponent.h" // Incluye esta directiva para acceder a Ak Component.
#include "AkSwitchValue.h" // Incluye esta directiva para acceder a Ak Switch Value.
#include "PhysicalMaterials/PhysicalMaterial.h" // Incluye esta directiva para poder trabajar con Physical Materials.

Declara un Ak Audio Component, un TMap, un booleano, y un float.

.h file:

/** Ak Audio Component. Creado en el constructor de la clase. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Audio")
UAkComponent* AkAudioComponent;

/** Un map es una structura de datos. Contiene Physical Materials como claves y floats como valores.
 *  Estos valores van a definir el switch correcto en Wwise. */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Audio")
TMap<UPhysicalMaterial*, UAkSwitchValue*> PhysicalMaterialMap;

/** Propiedad Booleana que define la visibilidad de la función AddOnScreenDebugMessage y hace que el line trace sea visible en el juego. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Audio")
bool bPrintDebug;

/** Define que tan lejos el line trace se extiende desde la posición de nuestro Character en el vector Z. 
 *  Números positivos vector hacia arriba, números negativos vector hacia abajo. -150cm definido por defecto */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Audio")
float Offset = -150;

Declara dos funciones, GetPhysicalMaterialByLineTrace() y SetFootstepsParameter().

.h file:

/**
 * @brief Obtiene una referencia del Physical Material del suelo con un line trace.
 * @param OffsetZ Qué tan lejos el line trace se extiende desde el centro de nuestro personaje.
 * @param bDebug Define la visibilidad del line trace. true: Visible, false: No Visible. 
 * @return una referencia del Physical Material 
 */
UFUNCTION(BlueprintCallable, Category="Audio")
UPhysicalMaterial* GetPhysicalMaterialByLineTrace(const float &OffsetZ, const bool &bDebug);

/**
 * @brief Obtiene una referencia del Physical Material y define el Ak Switch value apropiado en Wwise. 
 * @param HitPhysicalMaterial Una referencia del Physical Material. 
 * @param bDebug Define la visibilidad para imprimir el nombre del Physical Material actual en la pantalla. true: Visible, false: No Visible
 * @param DefaultAkSwitchValue El Ak Switch value por defecto.
 */
UFUNCTION(BlueprintCallable, Category="Audio")
void SetFootstepsSwitch(const UPhysicalMaterial* HitPhysicalMaterial, const bool &bDebug, const UAkSwitchValue* DefaultAkSwitchValue);

Implementación C++ y Blueprint:

En esta sección te muestro cómo acceder al Line trace en el Kismet System Library y cómo crear un Ak Audio Component. Finalmente, te muestro la implementación del BP_ThirdPersonCharacter en el graph blueprint y luego la implementación C++ en el archivo MyUE5ProjectCharacter.cpp.

.cpp file:

#include "Kismet/KismetSystemLibrary.h" // Incluye esta directiva para acceder a las funciones de line trace.

FMOD Audio Component en el Constructor de la Clase:

Crea un Ak Audio Component en el constructor. El constructor lleva el mismo nombre que su clase: MyUE5ProjectCharacter::MyUE5ProjectCharacter(). Este Ak Audio Component va a contener el Ak Audio Event de pasos, y va a seguir la posición del personaje en el mundo. Adicionalmente, este componente nos permite definir los switch values antes de crear una instancia de su evento.

.cpp file:

// Crea un Ak Audio Component. 
AkAudioComponent = CreateDefaultSubobject<UAkComponent>(TEXT("Footsteps Audio Component")); //Crea el Ak Audio Component.
AkAudioComponent->SetupAttachment(GetMesh()); // Vincula a este componente al Skeletal Mesh para que el sonido viaje con nuestro personaje.

Get Physical Material By LineTrace

Esta función crea un line trace y devuelve el Physical Material con el que colisiona.

Blueprint:

.cpp file:

UPhysicalMaterial* AMyUE5ProjectCharacter::GetPhysicalMaterialByLineTrace(const float &OffsetZ, const bool &bDebug)
{
   const FVector LineStart = GetActorLocation(); //Define el origen de la línea en la ubicación de nuestro personaje.
   const FVector LineEnd = FVector(LineStart.X, LineStart.Y, LineStart.Z + OffsetZ);  // Define el final de la línea en la posición de nuestro personaje más el offset. 
   EDrawDebugTrace::Type DebugType; // Esta enumeración es usada para definir la visibilidad del line trace.
   FHitResult HitResult; // Esta estructura va a contener los resultados de la colisión de la línea.   
	
   if (bDebug) // Activar la visibilidad de la línea?
	DebugType = EDrawDebugTrace::ForDuration;
   else                                          
	DebugType = EDrawDebugTrace::None;       

   // Función del line trace.
   UKismetSystemLibrary::LineTraceSingle(this, LineStart, LineEnd,UEngineTypes::ConvertToTraceType(ECC_Visibility), false,TArray<AActor*>(), DebugType, HitResult, true, FLinearColor::Red, FLinearColor::Red, 2.0f);
	
   return Cast<UPhysicalMaterial>(HitResult.PhysMaterial); // Hace un cast y devuelve el Physical Material desde HitResult.
}

Set Footsteps Parameter

Esta función obtiene una referencia del Physical Material e intenta encontrarla como una clave en nuestro TMap. Si tiene éxito, esta va a definir el valor relacionado con esta clave como el Ak Switch actual. Adicionalmente, va a imprimir el nombre del Physical Material actual en la pantalla.

Blueprint:

.cpp file:

void AMyUE5ProjectCharacter::SetFootstepsSwitch(const UPhysicalMaterial* HitPhysicalMaterial, const bool &bDebug, const UAkSwitchValue* DefaultAkSwitchValue)
{
/* Comprueba si el mapa contiene el Physical Material como clave antes de definir el Ak Switch Value.
*  El juego va generar un crash si intenta encontrar una referencia nula o la clave no existe en el mapa.*/
if (PhysicalMaterialMap.Contains(HitPhysicalMaterial)) 
{
	AkAudioComponent->SetSwitch(PhysicalMaterialMap[HitPhysicalMaterial], "", ""); // Define el Ak Switch Value usando el valor de la clave en el mapa. 

	if (bDebug) // Sí esta definido como true, imprime el nombre del Physical Material en la pantalla y "C++ Implementation".

	   {
	   GEngine->AddOnScreenDebugMessage(0, 1, FColor::Orange,
	   "Physical Material: " + HitPhysicalMaterial->GetName());
           GEngine->AddOnScreenDebugMessage(1, 1, FColor::Red, "C++ Implementation");
	   }
}
else // Si no se encontró una clave valida, define el valor del parámetro por defecto value = 0, de lo contrario el último valor se va a mantener.
   {
   AkAudioComponent->SetSwitch(DefaultAkSwitchValue, "", ""); 
   }
}

Full Blueprint Graph:

.cpp file:


Guarda tu código y compila en el editor.

 
 

You should be able to see the Ak Audio Component and all the properties in the components and variables tabs in the BP_ThirdPersonCharacter class. Assign your footsteps event to this component.


Animation Blueprint:

En el BP_ThirdPersonCharacter, ve a al Physical Material Map definido previamente en C++ y asigna los Physical Materials como claves. Llena los valores del mapa basado en los Ak Switch values definidos en Wwise.

Da click derecho en el graph y crea una función de tipo custom event function. Yo nombré a esta función BPF_PlayFootsteps. Finalmente, arrastra el Ak Audio Component hacia el graph y llama a su función Post Associated Ak Event.

Toda la funcionalidad para cambiar los Ak Switch values de forma dinámica, está lista. Ahora, debemos disparar el evento de pasos. Para lograr esto, implementa esta funcionalidad en el Animation Blueprint. Abre el Content Drawer, ve a Content > Characters > Mannequins > Animations, y abre ABP_Manny. Ve a la esquina superior derecha del editor y da click en el botón Animation Sequence.

En el Asset Browser, abre la secuencia "MF_Run_Fwd" sequence y añade un notify track. Luego, da click derecho en el y selecciona Add Notify > New Notify. Llama a tu notify "Footstep." Duplica tu notify en cada frame en donde los pies del skeletal mesh tocan el suelo. Repite el mismo proceso para las secuencias "MF_Walk_Fwd" y "MM_Walk_InPlace."

Regresa al Animation Blueprint y llama a la función Event Blueprint Begin Play para hacer un cast y guardar la referencia de BP_ThirdPersonCharacter en una variable apenas el juego empiece. Llama al notify buscando la función AnimNotify_Footstep. Finalmente, llama a la función BPF_PlayFootsteps.

Implementación Blueprint Completa:

En este proyecto cree una bifurcación o branch para seleccionar entre la implementación blueprint y la implementación C++ nativa.


EL FIN

〰️〰️〰️

EL FIN 〰️〰️〰️

Previous
Previous

Espacialización #1 en Unreal Engine y Wwise (Blueprints y C++)

Next
Next

Sistema de Pasos en Unreal Engine y FMOD (Blueprints y C++)