using System; using System.Collections.Generic; using System.Linq; using Core; using DG.Tweening; using Sirenix.Utilities; using UnityEngine; using Application = Core.Application; namespace PermanentSystems { public enum AudioList { BackgroundMusic, HitEffectA, HitEffectB, CollectEffectA, CollectEffectB, ButtonClickA, ButtonClickB, NewHighScoreEffect, JumpEffect, HealthUp, EnterBoost, DestroyObject } public class AudioSystem : SystemBase, ITick { [Serializable] private class Sound { public AudioList title; public AudioClip clip; [Range(0f, 1f)] public float volume = 1f; [Range(-3f, 3f)] public float pitch = 1f; // public bool loop; // [HideInInspector] public float timeStamp = 0f; } private static AudioSystem _instance; [SerializeField] private float trackFadeDuration; [SerializeField] private int sfxQueueCount = 5; [SerializeField] private Sound[] audios; private Dictionary _audioMap; private AudioSource _musicSource; private Queue _sfxSourceBuffer; private HashSet _sfxSources; private AudioList _currentMusicTrack; private float _globalSfxVol = 1f; private float _globalMusicVol = 1f; private PersistantDataController _dataController; private PersistantDataController DataController { get { if (_dataController == null) _dataController = Application.GetSystem(); return _dataController; } } protected override void ReleaseReferences() { _dataController = null; } public override void Initialize() { if (_instance != null) return; _instance = this; _musicSource = gameObject.AddComponent(); _sfxSources = new HashSet(); _sfxSourceBuffer = new Queue(); for (var i = 0; i < sfxQueueCount; i++) _sfxSourceBuffer.Enqueue(gameObject.AddComponent()); _audioMap = new Dictionary(); foreach (var sound in audios) _audioMap.Add(sound.title, sound); } private AudioSource GetSfxSource() { var source = (_sfxSourceBuffer == null || _sfxSourceBuffer.Count == 0) ? gameObject.AddComponent() : _sfxSourceBuffer.Dequeue(); _sfxSources.Add(source); return source; } public override void StartSystem() { UpdateMusicVolume(DataController.PlayerData.musicVolume); UpdateSfxVolume(DataController.PlayerData.soundEffectsVolume); base.StartSystem(); } public static void UpdateSfxVolume(float amount) => _instance._globalSfxVol = amount; public static void UpdateMusicVolume(float amount) { if (_instance == null) return; _instance._globalMusicVol = amount; _instance._musicSource.volume = amount * _instance._audioMap[_instance._currentMusicTrack].volume; } public static void PlaySoundEffect(AudioList trackName) { if (!_instance._audioMap.TryGetValue(trackName, out var track)) return; var source = _instance.GetSfxSource(); source.clip = track.clip; source.pitch = track.pitch; source.volume = _instance._globalSfxVol * track.volume; source.Play(); } public static void StopSoundEffects() { if (_instance._sfxSources == null || _instance._sfxSources.Count == 0) return; _instance._sfxSources.ForEach(src => src.Stop()); } public static void StopMusic(bool stopImmediate = true) { var duration = stopImmediate ? 0f : _instance.trackFadeDuration; var source = _instance._musicSource; source.DOFade(0f, duration) .OnComplete(() => source.Stop()); } public static void PlayMusicImmediate(AudioList trackName) { if (!_instance._audioMap.TryGetValue(trackName, out var track)) return; _instance._currentMusicTrack = trackName; var source = _instance._musicSource; source.clip = track.clip; source.pitch = track.pitch; source.loop = true; source.volume = _instance._globalMusicVol * track.volume; source.Play(); } public static void PlayMusic(AudioList trackName) { if (!_instance._audioMap.TryGetValue(trackName, out var track)) return; var source = _instance._musicSource; var duration = source.isPlaying ? _instance.trackFadeDuration : 0f; source.DOFade(0f, duration) .OnComplete(() => { _instance._currentMusicTrack = trackName; source.clip = track.clip; source.pitch = track.pitch; source.loop = true; // source.time = track.timeStamp; source.volume = 0f; source.Play(); source.DOFade(_instance._globalMusicVol * track.volume, _instance.trackFadeDuration); }); } public void Tick() { if (_sfxSources == null || _sfxSources.Count == 0) return; var completedSources = _sfxSources .Where(src => !src.isPlaying && !src.loop) .ToArray(); foreach (var src in completedSources) { _sfxSources.Remove(src); _sfxSourceBuffer.Enqueue(src); } } } }