Sistema de audio
El sistema de audio de OpenMon es un motor 2D basado en pooling de AudioSource sobre el AudioMixer de Unity. Está dividido en dos capas: Foundation (OpenMon.Foundation.Audio) provee el motor genérico de reproducción, y Core (OpenMon.MCE.Audio) agrega configuración de volumen y persistencia específica del juego.

Tres buses independientes (global, música y efectos), y el global multiplica a los otros dos en lugar de reemplazarlos, por eso silenciar la música no apaga el golpe de una batalla.
Arquitectura
| Clase | Capa | Propósito |
|---|---|---|
AudioManager | Foundation | Singleton que posee un pool de AudioSource y reproduce/para/fadea clips |
AudioLibrary | Foundation | ScriptableObject que registra cada AudioClip con su AudioMixerGroup |
AudioReference | Foundation | Struct serializable liviana que referencia un clip por nombre |
AudioSettingsManager | Core | Lee/escribe preferencias de volumen y las aplica al mixer |
AudioConfiguration | Core | Clase de datos serializable con niveles Master, Music y FX |
AudioInstaller | Foundation | ScriptableObjectInstaller de Zenject que bindea IAudioManager e IAudioLibrary |
AudioSettingsInstaller | Core | Installer de Zenject que bindea AudioSettingsManager y el AudioMixer |
AudioManager
AudioManager es un singleton (Singleton<AudioManager>) que implementa IAudioManager. Administra un pool dinámico de componentes AudioSource en su propio GameObject. Al reproducir, reusa una fuente libre del pool o crea una nueva si es necesario.
Reproducir audio
// One-shot simple
AudioManager.Instance.PlayAudio(miAudioReference);
// BGM en loop con fade-in
AudioManager.Instance.PlayAudio(bgmReference, loop: true, fadeTime: 1.5f);
// Pitch y volumen personalizados
AudioManager.Instance.PlayAudio(sfxReference, pitch: 1.2f, volume: 0.8f);
Cada llamada resuelve el AudioReference a través de la AudioLibrary, obtiene el clip y su mixer group, y los asigna a un AudioSource del pool. Cuando fadeTime > 0, el manager ejecuta una corrutina que interpola el volumen de 0 al target durante la duración especificada.
Detener audio
// Parada instantánea
AudioManager.Instance.StopAudio(bgmReference);
// Fade out en 2 segundos, luego para
AudioManager.Instance.StopAudio(bgmReference, fadeTime: 2f);
// Parada de emergencia (ej. abortar batalla)
AudioManager.Instance.StopAllAudios();
Silenciar / Reactivar global
Estas corrutinas operan sobre el parámetro MasterVolume del AudioMixer, permitiendo silenciar todo el output sin detener fuentes individuales. Útil para transiciones de escena y pantallas de pausa.
// Silenciar el bus master en 1 segundo
StartCoroutine(AudioManager.Instance.MuteAllAudios(fadeTime: 1f));
// Restaurar al volumen anterior
StartCoroutine(AudioManager.Instance.UnmuteAllAudios(fadeTime: 1f));
Ciclo de vida del pool
El pool se auto-administra. Cada frame, CheckAudioSourceAvailability() escanea todas las fuentes. Cualquier fuente que haya terminado de reproducir se marca como disponible y se limpia su referencia al clip. Si ningún otro fuente está usando ese clip, se notifica a la librería vía FreeAudioAsset() para permitir descarga futura basada en addressables.
AudioLibrary
AudioLibrary es un ScriptableObject (crear via OpenMon > Audio > Audio Library) que funciona como registro central de audio. Almacena un SerializableDictionary<AudioClip, AudioMixerGroup> que mapea cada clip del juego al mixer group por el que debe reproducirse (BGM, SFX, ME, etc.).
AudioLibrary (ScriptableObject)
+-- "battle_bgm_01" -> BGM MixerGroup
+-- "ui_confirm" -> SFX MixerGroup
+-- "level_up_jingle" -> ME MixerGroup
+-- "cry_001" -> SFX MixerGroup
...
En tiempo de edición, la librería cachea listas planas de nombres, referencias a clips y mixer groups para búsqueda O(n) por nombre. El comando Cache Audio References del menú contextual reconstruye estos caches al agregar o quitar clips.
Utilidad de editor
El pipeline del importer puede registrar clips automáticamente:
audioLibrary.AddAudioIfItsNotIn(clip, mixerGroup);
AudioReference
AudioReference es un struct serializable simple con un solo campo string Audio. Coincide con el nombre del clip registrado en la AudioLibrary. Esto desacopla los datos serializados de escenas/prefabs de referencias directas a clips, permitiendo reorganizar archivos de audio sin romper referencias del inspector.
[Serializable]
public struct AudioReference
{
public string Audio; // Debe coincidir con un nombre en AudioLibrary
}
Usá campos AudioReference en tus MonoBehaviours, ScriptableObjects o nodos de CommandGraph para referenciar audio por nombre.
AudioSettingsManager
AudioSettingsManager es el controlador de volumen específico del juego. Lee AudioConfiguration del sistema de configuración persistente y aplica tres niveles al AudioMixer:
- MasterVolume — volumen general del juego
- MusicVolume — volumen del grupo BGM
- FXVolume — volumen de efectos de sonido y jingles
Conversión de volumen
La percepción humana del volumen es logarítmica. El sistema usa AudioUtils para convertir entre el rango lineal 0-1 de los sliders y la escala en decibelios que espera el AudioMixer de Unity:
float db = AudioUtils.LinearVolumeToLogarithmicVolume(0.5f); // ~ -6 dB
float linear = AudioUtils.LogarithmicVolumeToLinearVolume(-6f); // ~ 0.5
Persistir configuración
Las preferencias de volumen se guardan via el sistema IConfigurationManager. Cuando el jugador ajusta un slider en la pantalla de opciones, la UI llama a:
audioSettingsManager.SetAudioConfiguration(new AudioConfiguration
{
MasterVolume = masterSlider.value,
MusicVolume = musicSlider.value,
FXVolume = fxSlider.value
});
Esto escribe la configuración a disco y aplica los nuevos valores al mixer inmediatamente. Al iniciar, AudioSettingsManager.Construct() se llama via inyección Zenject y aplica la configuración guardada en el siguiente frame.
Setup de inyección de dependencias
Ambos installers son ScriptableObjectInstaller de Zenject agregados al SceneContext de la escena:
- AudioInstaller — bindea
IAudioManager(desdeAudioManager.Instance),IAudioLibrary(desde el assetAudioLibrary), y elAudioMixer. - AudioSettingsInstaller — bindea
AudioSettingsManagercomo singleton lazy e inyecta elAudioMixer.
SceneContext
+-- AudioInstaller (referencia al asset AudioLibrary + AudioMixer)
+-- AudioSettingsInstaller (referencia al AudioMixer)
Usar audio en CommandGraph
La reproducción de audio se puede disparar desde scripts de eventos de NPC (CommandGraph). La categoría Sounds tiene los nodos: PlayMusic (una pista como música del mundo, por encima de la propia del mapa), StopMusic (la desvanece), SaveMusic y RestoreSceneMusic (conservan una pista tras una batalla, o vuelven a la del propio mapa), PlaySound, PlayMonsterCry y WaitForAudio (detiene el grafo hasta que termina un jingle). Los nodos referencian clips via campos AudioReference, que se resuelven a través de la misma AudioLibrary en runtime. Para llenar la biblioteca con los clips que ya hay en tu proyecto, usa Tools > MCE > Audio > Populate Audio Library.
Resumen
| Si querés... | Usá... |
|---|---|
| Reproducir un efecto de sonido | AudioManager.Instance.PlayAudio(ref) |
| Poner música de fondo en loop | AudioManager.Instance.PlayAudio(ref, loop: true) |
| Crossfade a un nuevo BGM | Detener el anterior con fadeTime, reproducir el nuevo con fadeTime |
| Silenciar durante carga de escena | MuteAllAudios(fadeTime) / UnmuteAllAudios(fadeTime) |
| Registrar un clip nuevo | Agregalo al asset AudioLibrary y asignale un mixer group |
| Ajustar volumen del jugador | AudioSettingsManager.SetAudioConfiguration(config) |
| Convertir slider a dB | AudioUtils.LinearVolumeToLogarithmicVolume(value) |