sea-battle/Assets/Scripts/SoundManager.cs
2026-01-09 08:45:22 +03:00

389 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// SoundManager
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SoundManager : MonoBehaviour
{
public static SoundManager Instance;
[Header("Player 1 AudioSources")]
public AudioSource player1VoiceSource;
public AudioSource player1EffectsSource;
[Header("Player 2 AudioSources")]
public AudioSource player2VoiceSource;
public AudioSource player2EffectsSource;
[Header("Фоновая музыка")]
public AudioSource musicSource;
public AudioClip[] backgroundMusic;
private int currentTrackIndex = -1;
[Header("Общие эффекты")]
public AudioClip[] shootSounds;
public AudioClip[] explosionSounds;
[Header("Профили звуков")]
public List<SoundProfile> soundProfiles;
[Header("Cooldowns (сек)")]
public float generalCooldown = 0.25f;
[Header("Настройки повторений")]
[Tooltip("Количество последних клипов, которые не будут повторяться")]
public int avoidLastClipsCount = 3;
private Dictionary<string, SoundProfile> profileLibrary = new Dictionary<string, SoundProfile>();
private Dictionary<int, SoundProfile> activeProfiles = new Dictionary<int, SoundProfile>();
private Dictionary<string, float> lastPlayTimes = new Dictionary<string, float>();
private Dictionary<int, int> currentVoicePriority = new Dictionary<int, int>();
// Словарь для хранения последних воспроизведённых клипов по каждому ключу
private Dictionary<string, Queue<AudioClip>> recentlyPlayedClips = new Dictionary<string, Queue<AudioClip>>();
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
UnityEngine.Object.Destroy(base.gameObject);
}
UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
profileLibrary.Clear();
foreach (SoundProfile soundProfile in soundProfiles)
{
if (soundProfile != null && !profileLibrary.ContainsKey(soundProfile.profileName))
{
profileLibrary.Add(soundProfile.profileName, soundProfile);
}
}
}
private void Start()
{
ApplyAudioSettings();
if (backgroundMusic.Length != 0 && musicSource != null)
{
StartCoroutine(MusicLoop());
}
}
private void OnEnable()
{
if (SettingsManager.instance != null)
{
SettingsManager.instance.OnSettingsChanged.AddListener(ApplyAudioSettings);
}
}
private void OnDisable()
{
if (SettingsManager.instance != null)
{
SettingsManager.instance.OnSettingsChanged.RemoveListener(ApplyAudioSettings);
}
}
private void ApplyAudioSettings()
{
float volume = (float)Convert.ToInt32(SettingsManager.instance.GetSettingValue("Громкость музыки")) / 10f;
float volume2 = (float)Convert.ToInt32(SettingsManager.instance.GetSettingValue("Громкость эффектов")) / 10f;
float volume3 = (float)Convert.ToInt32(SettingsManager.instance.GetSettingValue("Громкость голоса")) / 10f;
musicSource.volume = volume;
player1VoiceSource.volume = volume2;
player1EffectsSource.volume = volume3;
player2VoiceSource.volume = volume2;
player2EffectsSource.volume = volume3;
}
private IEnumerator MusicLoop()
{
while (true)
{
PlayNextTrack();
yield return new WaitForSeconds(musicSource.clip.length);
}
}
private void PlayNextTrack()
{
if (backgroundMusic.Length != 0)
{
int num = UnityEngine.Random.Range(0, backgroundMusic.Length);
if (num == currentTrackIndex && backgroundMusic.Length > 1)
{
num = (num + 1) % backgroundMusic.Length;
}
currentTrackIndex = num;
musicSource.clip = backgroundMusic[currentTrackIndex];
musicSource.Play();
}
}
public void PlayVoice(int playerId, AudioClip clip)
{
if (clip == null) return;
AudioSource source = GetVoiceSource(playerId);
// Прерываем предыдущую фразу, если нужно (для голоса это обычно желательно)
source.Stop();
source.PlayOneShot(clip);
}
public void SetActiveProfile(int playerId, string profileName)
{
if (profileLibrary.TryGetValue(profileName, out var value))
{
activeProfiles[playerId] = value;
Debug.Log($"[SoundManager] Игрок {playerId} активировал профиль '{profileName}'");
}
else
{
Debug.LogWarning("[SoundManager] Профиль '" + profileName + "' не найден!");
}
}
private bool CanPlay(string key, float cooldown)
{
if (!lastPlayTimes.TryGetValue(key, out var value))
{
value = 0f;
}
if (Time.time - value < cooldown)
{
return false;
}
lastPlayTimes[key] = Time.time;
return true;
}
/// <summary>
/// Выбирает случайный клип из массива, избегая недавно воспроизведённых
/// </summary>
// private AudioClip GetRandomClipAvoidingRecent(AudioClip[] clips, string key)
// {
// if (clips == null || clips.Length == 0)
// return null;
//
// // Ограничиваем размер истории количеством клипов (минус 1, чтобы был хоть 1 доступный)
// int effectiveAvoidCount = Mathf.Min(avoidLastClipsCount, clips.Length - 1);
//
// // Получаем список недавно воспроизведённых
// if (!recentlyPlayedClips.TryGetValue(key, out Queue<AudioClip> recentQueue))
// {
// recentQueue = new Queue<AudioClip>();
// recentlyPlayedClips[key] = recentQueue;
// Debug.Log($"<color=cyan>[SoundManager] {key}: Создана новая история воспроизведения (макс: {effectiveAvoidCount})</color>");
// }
//
// // Показываем текущую историю
// List<string> clipNames = new List<string>();
// foreach (AudioClip clip in recentQueue)
// {
// clipNames.Add(clip != null ? clip.name : "null");
// }
// string recentHistory = string.Join(", ", clipNames);
// Debug.Log($"<color=yellow>[SoundManager] {key}: История ({recentQueue.Count}/{effectiveAvoidCount}): [{recentHistory}]</color>");
//
// // Создаём список доступных клипов (которые не были недавно воспроизведены)
// List<AudioClip> availableClips = new List<AudioClip>();
// foreach (AudioClip clip in clips)
// {
// if (!recentQueue.Contains(clip))
// {
// availableClips.Add(clip);
// }
// }
//
// Debug.Log($"<color=yellow>[SoundManager] {key}: Всего клипов: {clips.Length}, Доступно: {availableClips.Count}</color>");
//
// // Если все клипы недавно воспроизводились - очищаем историю и используем все
// if (availableClips.Count == 0)
// {
// Debug.Log($"<color=orange>[SoundManager] {key}: Все клипы в истории! Очищаем историю и начинаем заново.</color>");
// recentQueue.Clear();
// availableClips.AddRange(clips);
// }
//
// // Выбира<D180><D0B0>м случайный из доступных
// AudioClip selectedClip = availableClips[UnityEngine.Random.Range(0, availableClips.Count)];
//
// Debug.Log($"<color=lime>[SoundManager] {key}: ▶ Выбран клип: {selectedClip.name}</color>");
//
// // Добавляем в историю
// recentQueue.Enqueue(selectedClip);
//
// // Ограничиваем размер очереди ЭФФЕКТИВНЫМ значением
// while (recentQueue.Count > effectiveAvoidCount)
// {
// AudioClip removed = recentQueue.Dequeue();
// Debug.Log($"<color=gray>[SoundManager] {key}: Удалён из истории: {removed.name}</color>");
// }
//
// return selectedClip;
// }
private AudioSource GetVoiceSource(int playerId)
{
if (playerId != 1)
{
return player2VoiceSource;
}
return player1VoiceSource;
}
private AudioSource GetEffectsSource(int playerId)
{
if (playerId != 1)
{
return player2EffectsSource;
}
return player1EffectsSource;
}
private void StopAllPlayerSounds(int playerId)
{
GetVoiceSource(playerId).Stop();
GetEffectsSource(playerId).Stop();
currentVoicePriority[playerId] = 0;
}
private void PlayClip(AudioClip clip, int playerId, bool isVoice = true, bool interrupt = false, int priority = 1)
{
if (clip == null)
{
return;
}
AudioSource audioSource = (isVoice ? GetVoiceSource(playerId) : GetEffectsSource(playerId));
if (isVoice)
{
if (!currentVoicePriority.ContainsKey(playerId))
{
currentVoicePriority[playerId] = 0;
}
int num = currentVoicePriority[playerId];
if (audioSource.isPlaying && num > priority)
{
Debug.Log($"[SoundManager] Игрок {playerId}: пропустил звук (prio {priority} < {num})");
return;
}
if (audioSource.isPlaying && num == priority && !interrupt)
{
Debug.Log($"[SoundManager] Игрок {playerId}: звук равного приоритета, не прерываем.");
return;
}
currentVoicePriority[playerId] = priority;
}
if (interrupt)
{
audioSource.Stop();
audioSource.clip = clip;
audioSource.Play();
}
else
{
audioSource.PlayOneShot(clip);
}
if (isVoice)
{
StartCoroutine(ResetVoicePriorityAfter(clip.length, playerId, priority));
}
}
private IEnumerator ResetVoicePriorityAfter(float delay, int playerId, int priority)
{
yield return new WaitForSeconds(delay);
if (currentVoicePriority.TryGetValue(playerId, out var value) && value == priority)
{
currentVoicePriority[playerId] = 0;
}
}
// private void PlayRandom(AudioClip[] clips, int playerId, string key, bool isVoice = true, bool interrupt = false, int priority = 1)
// {
// if (clips != null && clips.Length != 0 && CanPlay(key, generalCooldown))
// {
// AudioClip clip = GetRandomClipAvoidingRecent(clips, key);
// if (clip != null)
// {
// PlayClip(clip, playerId, isVoice, interrupt, priority);
// }
// }
// }
// public void PlayPlayerHit(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.playerHit, playerId, $"PlayerHit_{playerId}");
// }
//
// public void PlayPlayerMiss(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.playerMiss, playerId, $"PlayerMiss_{playerId}");
// }
//
// public void PlayBotHit(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.botHit, playerId, $"BotHit_{playerId}");
// }
//
// public void PlayBotMiss(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.botMiss, playerId, $"BotMiss_{playerId}");
// }
//
// public void PlayPlayerShipDestroyed(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.playerShipDestroyed, playerId, $"PlayerShipDestroyed_{playerId}", isVoice: true, interrupt: true, 2);
// }
//
// public void PlayBotShipDestroyed(int playerId)
// {
// PlayRandom(activeProfiles[playerId]?.botShipDestroyed, playerId, $"BotShipDestroyed_{playerId}", isVoice: true, interrupt: true, 2);
// }
//
// public void PlayPlayerVictory(int playerId)
// {
// StopAllPlayerSounds(playerId);
// PlayRandom(activeProfiles[playerId]?.playerVictory, playerId, $"PlayerVictory_{playerId}", isVoice: true, interrupt: true, 3);
// }
//
// public void PlayBotVictory(int playerId)
// {
// StopAllPlayerSounds(playerId);
// PlayRandom(activeProfiles[playerId]?.botVictory, playerId, $"BotVictory_{playerId}", isVoice: true, interrupt: true, 3);
// }
public void PlayShoot(int playerId)
{
if (shootSounds.Length != 0)
{
AudioClip clip = shootSounds[UnityEngine.Random.Range(0, shootSounds.Length)];
GetEffectsSource(playerId).PlayOneShot(clip);
}
}
public void PlayExplosion(int playerId)
{
if (explosionSounds.Length != 0)
{
AudioClip clip = explosionSounds[UnityEngine.Random.Range(0, explosionSounds.Length)];
GetEffectsSource(playerId).PlayOneShot(clip);
}
}
}