233 lines
7.4 KiB
C#

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<AudioClip> 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
}
}