Cómo crear un Audio Manager en Unreal Engine
If you prefer to read an English version, click on this button =>
Unreal Engine Version: 5.2.1
Este blog post muestra cómo crear un audio manager usando un Game Instance Subsystem en Unreal Engine.
La única forma de crear y configurar un Game Instance Subsystem es usando código C++ nativo; desafortunadamente, no hay manera de crear este manager usando solo Blueprint. A pesar de esto, toda la funcionalidad que se construya en este Manager de Audio, debería ser de fácil acceso y extendible por medio de scripting visual.
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:
Crea un proyecto C++ first-person o third-person llamado “MyUEProject.”
IMPORTANTE!
〰️
IMPORTANTE! 〰️
The Gameplay Framework
“The Gameplay Framework in Unreal Engine provides multiple classes and components to serve as building blocks for your projects”
Traducción:
“El Gameplay Framework (Estructura de Juego), provee una variedad de clases y componentes que sirven cómo piezas de construcción para tus proyectos“
Epic Games
El abordar todas las clases y funcionalidad del gameplay framework está fuera del alcance de este blog post. Para nuestro propósito actual voy a enfocarme en el Game Instance y en el Game Instance Subsystem. Si te gustaría aprender más sobre el Gameplay Framework, recomiendo ver estos vídeos de Epic Online Learning y también leer la documentación oficial:
Game Instance y Game Instance Subsystem:
Aquí algunos datos esenciales sobre el Game Instance:
Es creado antes del resto de clases en el Gameplay Framework y el mundo (world)
Es destruido despues de todas las demas clases al cerrar el juego.
Persiste durante la carga, creación y destrucción del mundo.
Se puede acceder a él de forma global desde cualquier lugar del proyecto.
Solo una instancia existe por sesión de juego (comportamiento Singleton)
Entonces, este es una gran clase de tipo manager, y funcionaría muy bien si le añadimos nuestra funcionalidad de manejo del audio. A pesar de esto, si cada disciplina de nuestro equipo de desarrollo haría lo mismo, el Game Instance terminaría siendo una clase enorme con miles de líneas de código. Esto no es una buena idea!
Unreal Engine provee un “módulo” o “componente” para el Game Instance llamada Game Instance Subsystem que resuelve este problema.
Un Game Instance Subsystem provee la misma funcionalidad y se comporta como el Game Instance pero nos permite "modularizar” nuestro código para que sea fácil de mantener y escalar.
Cuando el Game Instance inicializa, inmediatamente inicializa los demás sub-sistemas después. Entonces, podemos estar seguros de que nuestro nuevo manager estará listo cuando el juego empiece.
Audio Subsystem - Audio Manager
Para añadir un Game Instance Subsystem, crea una nueva clase C++ derivada de UGameInstanceSubsystem llamada “MyAudioSubsystem.”
Un archivo .h y .cpp serán creados en la carpeta “source”.
BP_MyAudioSubsystem
Para que este nuevo Manager de Audio sea útil para nosotros los diseñadores de audio, es esencial crear una representación blueprint (.uasset) de este para que podamos asignarle los assets que este manager va a usar.
Algunos ejemplos de assets que sería útil incluir son estados o parametros globales, asignaciones de superficies físicas (physical surfaces), buses de mezcla, eventos de música, e instancias de audio que deban persistir a lo largo del loop del juego.
Dentro del macro UCLASS, añade el especificador Blueprintable. Este permite la creación de la versión Blueprint de este subsistema. El especificador Abstract define que la versión C++ del subsistema de audio es solo un arquetipo, lo que significa que los datos añadidos a la versión blueprint serán usados por el juego.
Después de re-compilar el código, crea un nuevo blueprint derivado de UMyAudioSubsystem llamado BP_MyAudioSubsystem
Blueprint Subsystem Initializer
Desafortunadamente, las versiones Blueprint (.uasset) de un Game Instance Subsystem no son cargadas por el mundo por defecto, lo que significa que un paso adicional es necesario para hacerlos funcionar de forma apropiada.
Esta es una forma de hacerlo:
Crea una nueva clase C++ derivada de UDeveloperSettings llamada MyBlueprintSubsystemInitializer. Un archivo .h y .cpp serán creados en la carpeta “source”.
Haz que esta clase guarde a sus miembros dentro del archivo DefaultGame.ini. Para lograr esto, incluye los especificadores config = Game y DefaultConfig. Crea un array de UGameInstanceSubsystems para que después se puedan incluir nuevos y varios tipos de subsistemas. Dentro de este archivo .h, crea una nueva clase GameInstanceSubsystem y usa su función Initialize() para inicializar tu nuevo Subsistema Blueprint.
MyBlueprintSubsystemInitializer.h
MyBlueprintSubsystemInitializer.cpp
DefaultGame.ini y Project Settings
Después de compilar tu código, da click en Edit -> Project Settings y busca la sección Game. Un a nueva sub-sección llamada “Blueprint Subsystems” aparecerá . Asigna tu nuevo BP_MyAudioSubsystem al array.
Para verificar que tu subsistema se ha asignado al DefaultGame.ini, ve a la carpeta de tu proyecto en tu IDE o explorador y abre la carpeta “Config.”
Ruta: MyUEProject/Config
Ahora, el Audio Manager está listo para cualquier dato y función que quieras implementar. El cielo es el límite!
Implementación
En esta sección, demuestro cómo añadir datos y llamar y extender funciones en nuestro nuevo subsistema.
Añade una variable de tipo FString con dos funciones BlueprintImplementableFunction() y BlueprintExtendableFunction(), con un argumento de tipo UObject* que va a servir como un Objecto Contextual en el Mundo. Usa el macro UFUNCTION con especificadores BlueprintImplementableEvent y BlueprintNativeEvent lo que permite a los diseñadores implementar estas funciones en Blueprint sin tener que tocar código.
MyAudioSubsystem.h:
MyAudioSubsystem.cpp:
Compila el código y abre BP_MyAudioSubsystem. Llena el campo FString “MyTestString”.
Implementa ambas BlueprintImplementableFunction() y BlueprintExtendableFunction() en el Blueprint graph.
Cómo Usarlo?
Tal cómo mencioné anteriormente, el beneficio de usar un Game Instance Subsystem es que es de acceso global. Para estos ejemplos, usé el Blueprint del Nivel para probar estas nuevas funciones.
Para llamar al subistema, da click derecho en el graph y escribe MyAudioSubsystem.
Arrastra desde este nuevo nodo y llama a sus funciones en BeginPlay()
Finalmente, aquí muestro cómo acceder a este subsistema en C++ desde cualquier clase de tipo Actor: