using System.Text; using System.Collections.Generic; using UnityEngine; using UnityEngine.Audio; public class SoundManager : MonoBehaviour { [Header("Источники")] [SerializeField] private AudioSource MusicSrc; [SerializeField] private AudioSource UiSrc; [SerializeField] private AudioSource ReplicasSrc; [Header("Микшер")] [SerializeField] private AudioMixer mixer; [Header("Группы")] [SerializeField] private AudioMixerGroup MasterGroup; [SerializeField] private AudioMixerGroup MenuGroup; [SerializeField] private AudioMixerGroup UiGroup; [SerializeField] private AudioMixerGroup MusicGroup; [SerializeField] private AudioMixerGroup GameplayGroup; [SerializeField] private AudioMixerGroup SfxGroup; [SerializeField] private AudioMixerGroup ReplicasGroup; [SerializeField] private AudioMixerGroup EnvironmentGroup; const string GAMEPLAY_VOLUME = "GameplayVolume"; const string MASTER_VOLUME = "MasterVolume"; const string MENU_VOLUME = "MenuVolume"; private static SoundManager instance; public static bool Initialized { get; private set; } = false; public void Initialize() { if (Initialized) { Debug.LogWarning("Trying to initialize initialized SoundManager"); return; } instance = this; //Подтянуть настройки PullSettings(); SettingsManager.SettingsSaved += PullSettings; //Валидация ссылок var validationResult = ValidateReferences(); if (!validationResult.OK) { Initialized = false; Debug.LogError(validationResult.Message, instance); return; } //Установка каналов MusicSrc.outputAudioMixerGroup = MusicGroup; UiSrc.outputAudioMixerGroup = UiGroup; ReplicasSrc.outputAudioMixerGroup = ReplicasGroup; Initialized = true; DontDestroyOnLoad(gameObject); } public static void PlayMusic() { if (CheckInitialized()) instance.MusicSrc.Play(); } public static void StopMusic() { if (CheckInitialized()) instance.MusicSrc.Stop(); } public static void PlayUi(AudioClip clip) { if (CheckInitialized()) { if (clip == null) { Debug.Log("UI clip to play is null"); return; } instance.UiSrc.PlayOneShot(clip); } } public static void PlayReplica(AudioClip clip) { if (CheckInitialized()) { if (clip == null) { Debug.Log("Replica clip to play is null"); return; } instance.ReplicasSrc.PlayOneShot(clip); } } //Перегрузка для рандомного выбора из списка public static void PlayReplica(List clips) { if (CheckInitialized()) { if (clips == null || clips.Count == 0) { Debug.Log("Replica clip to play is null or count is 0"); return; } var clip = clips[Random.Range(0, clips.Count)]; instance.ReplicasSrc.PlayOneShot(clip); } } public static void AssignSourceToChannel(AudioSource source, MixerChannel channel) { if (CheckInitialized()) { if (source == null) { Debug.LogError("Source to assign is null"); return; } source.outputAudioMixerGroup = ChannelFromEnum(channel); } } private static AudioMixerGroup ChannelFromEnum(MixerChannel channel) { return channel switch { MixerChannel.Master => instance.MasterGroup, MixerChannel.Menu => instance.MenuGroup, MixerChannel.UI => instance.UiGroup, MixerChannel.Music => instance.MusicGroup, MixerChannel.Gameplay => instance.GameplayGroup, MixerChannel.SFX => instance.SfxGroup, MixerChannel.Replicas => instance.ReplicasGroup, MixerChannel.Environment => instance.EnvironmentGroup, _ => instance.MasterGroup, }; } private static bool CheckInitialized() { if (Initialized) return true; Debug.LogError("Trying use non initialized sound manager"); return false; } private static (bool OK, string Message) ValidateReferences() { var sb = new StringBuilder(); sb.AppendLine("[Sound Manager Validation]"); bool hasErrors = false; if (instance.MusicSrc == null) { sb.AppendLine("MusicSrc is not assigned!"); hasErrors = true; } if (instance.UiSrc == null) { sb.AppendLine("UiSrc is not assigned!"); hasErrors = true; } if (instance.ReplicasSrc == null) { sb.AppendLine("ReplicasSrc is not assigned!"); hasErrors = true; } if (instance.mixer == null) { sb.AppendLine("AudioMixer is not assigned!"); hasErrors = true; } if (instance.MasterGroup == null) { sb.AppendLine("MasterGroup is not assigned!"); hasErrors = true; } if (instance.MenuGroup == null) { sb.AppendLine("MenuGroup is not assigned!"); hasErrors = true; } if (instance.UiGroup == null) { sb.AppendLine("UiGroup is not assigned!"); hasErrors = true; } if (instance.MusicGroup == null) { sb.AppendLine("MusicGroup is not assigned!"); hasErrors = true; } if (instance.GameplayGroup == null) { sb.AppendLine("GameplayGroup is not assigned!"); hasErrors = true; } if (instance.SfxGroup == null) { sb.AppendLine("SfxGroup is not assigned!"); hasErrors = true; } if (instance.ReplicasGroup == null) { sb.AppendLine("ReplicasGroup is not assigned!"); hasErrors = true; } if (instance.EnvironmentGroup == null) { sb.AppendLine("EnvironmentGroup is not assigned!"); hasErrors = true; } if (hasErrors) { sb.AppendLine("Please assign all missing references in the inspector!"); } return (!hasErrors, sb.ToString()); } private void PullSettings() { SetMixerVolume(MASTER_VOLUME, SettingsManager.GetFloat(SettingKey.MasterVolume)); SetMixerVolume(GAMEPLAY_VOLUME, SettingsManager.GetFloat(SettingKey.GameVolume)); SetMixerVolume(MENU_VOLUME, SettingsManager.GetFloat(SettingKey.MenuVolume)); } private void SetMixerVolume(string parameterName, float value) { if (mixer == null) { Debug.LogError("Master mixer is not assigned!"); return; } // Конвертируем линейное значение (0-1) в децибелы // -80dB это практически тишина (минимальное значение) // 0dB это максимальная громкость float dB; if (value <= 0.001f) { dB = -80f; // Полная тишина } else { dB = Mathf.Log10(value) * 20f; // Ограничиваем минимальным значением -80dB dB = Mathf.Max(dB, -80f); } mixer.SetFloat(parameterName, dB); } public enum MixerChannel { Master, Menu, UI, Music, Gameplay, SFX, Replicas, Environment } }