389 lines
14 KiB
C#
389 lines
14 KiB
C#
// 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);
|
||
}
|
||
}
|
||
}
|