using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class AudioManager : MonoBehaviour { public static AudioManager Instance; [Header("Audio Sources")] public AudioSource musicSource; // We'll assign MusicPlayer here public AudioSource sfxSource; // For sound effects [Header("Music Library")] [Tooltip("Add your music files here")] public AudioClip[] musicLibrary; [Tooltip("Should music shuffle randomly?")] public bool shuffleMusic = true; [Tooltip("Should music loop the playlist?")] public bool loopPlaylist = true; [Tooltip("Time to fade between tracks (seconds)")] public float fadeDuration = 2f; [Header("UI Elements")] public Slider volumeSlider; // We'll assign VolumeSlider here [Header("Volume Settings")] [Range(0f, 1f)] public float masterVolume = 1f; [Range(0f, 1f)] public float musicVolume = 1f; [Range(0f, 1f)] public float sfxVolume = 1f; [Header("Current Track Info")] [SerializeField] private int currentTrackIndex = 0; [SerializeField] private bool isPlaying = false; [SerializeField] private bool isFading = false; private List shuffledIndices; private int shufflePosition = 0; void Awake() { // Singleton pattern if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); // Subscribe to scene loaded events to refresh UI UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded; } void OnDestroy() { // Unsubscribe from scene events UnityEngine.SceneManagement.SceneManager.sceneLoaded -= OnSceneLoaded; } // Called when a new scene loads void OnSceneLoaded(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode) { Debug.Log($"AudioManager: Scene '{scene.name}' loaded. Current volume before setup: {musicVolume}"); // Reset volumeSlider reference since it's a new scene volumeSlider = null; // Delay setup to ensure all UI elements are initialized StartCoroutine(DelayedUISetup()); } IEnumerator DelayedUISetup() { // Wait a frame for UI to initialize yield return new WaitForEndOfFrame(); // Re-load volume settings to ensure they're current LoadVolumeSettings(); Debug.Log($"AudioManager: Volume reloaded from PlayerPrefs: {musicVolume}"); // Setup UI sliders with current volume values SetupUISliders(); // Ensure volume is applied correctly to audio source ApplyVolumeSettings(); // If music is playing, ensure it has correct volume if (musicSource != null && musicSource.isPlaying) { musicSource.volume = musicVolume * masterVolume; Debug.Log($"AudioManager: Applied volume {musicVolume * masterVolume} to currently playing track"); } Debug.Log($"AudioManager: Scene setup complete. Final volume: {musicVolume}"); } void Start() { Debug.Log("AudioManager: Start() beginning..."); // Quick validation of music library ValidateMusicLibrary(); // Load saved volume settings FIRST (fastest operation) LoadVolumeSettings(); // Apply loaded volumes to audio sources ApplyVolumeSettings(); // Setup UI if available and sync with loaded values SetupUISliders(); // Initialize music library (do this last) InitializeMusicLibrary(); // Start playing music if we have tracks (this should be instant with streaming) if (musicLibrary.Length > 0) { StartPlayingMusic(); } Debug.Log("AudioManager: Start() completed"); } void ValidateMusicLibrary() { if (musicLibrary == null || musicLibrary.Length == 0) { Debug.LogWarning("AudioManager: No music tracks assigned!"); return; } int validTracks = 0; for (int i = 0; i < musicLibrary.Length; i++) { if (musicLibrary[i] != null) { validTracks++; // Log potential performance issues if (musicLibrary[i].length > 300) // 5+ minutes { Debug.LogWarning($"Track '{musicLibrary[i].name}' is very long ({musicLibrary[i].length:F1}s). Consider shorter tracks for better performance."); } } } Debug.Log($"AudioManager: {validTracks}/{musicLibrary.Length} valid music tracks loaded"); } // New method to properly setup UI sliders with saved values void SetupUISliders() { // Find volume slider in the current scene if not assigned if (volumeSlider == null) { volumeSlider = FindSliderByName("VolumeSlider", "MusicSlider", "Music Volume", "Volume"); Debug.Log($"AudioManager: Searching for volume slider in scene..."); } if (volumeSlider != null) { Debug.Log($"AudioManager: Found volume slider '{volumeSlider.gameObject.name}' with current value {volumeSlider.value}"); // Remove any existing listeners to prevent conflicts volumeSlider.onValueChanged.RemoveAllListeners(); // Set slider to saved volume value WITHOUT triggering events volumeSlider.SetValueWithoutNotify(musicVolume); // Add listener for future changes volumeSlider.onValueChanged.AddListener(SetMusicVolume); Debug.Log($"AudioManager: Volume slider set to {musicVolume} and listener added"); } else { Debug.Log("AudioManager: No volume slider found in current scene"); // List all sliders for debugging Slider[] allSliders = FindObjectsByType(FindObjectsSortMode.None); Debug.Log($"AudioManager: Found {allSliders.Length} sliders in scene:"); foreach (var slider in allSliders) { Debug.Log($" - {slider.gameObject.name} (value: {slider.value})"); } } } // Helper method to find volume slider by common names Slider FindSliderByName(params string[] possibleNames) { Slider[] allSliders = FindObjectsByType(FindObjectsSortMode.None); foreach (Slider slider in allSliders) { foreach (string name in possibleNames) { if (slider.gameObject.name.ToLower().Contains(name.ToLower())) { return slider; } } } return null; } public void SetMasterVolume(float volume) { masterVolume = Mathf.Clamp01(volume); PlayerPrefs.SetFloat("MasterVolume", masterVolume); ApplyVolumeSettings(); } public void SetMusicVolume(float volume) { Debug.Log($"AudioManager: SetMusicVolume called with {volume}. Previous volume: {musicVolume}"); Debug.Log($"AudioManager: Call stack: {System.Environment.StackTrace}"); musicVolume = Mathf.Clamp01(volume); PlayerPrefs.SetFloat("MusicVolume", musicVolume); PlayerPrefs.Save(); // Force save immediately ApplyMusicVolume(); Debug.Log($"AudioManager: Volume saved to PlayerPrefs and applied: {musicVolume}"); } public void SetSFXVolume(float volume) { sfxVolume = Mathf.Clamp01(volume); PlayerPrefs.SetFloat("SFXVolume", sfxVolume); ApplySFXVolume(); } // Legacy method for compatibility public void SetVolume(float volume) { SetMusicVolume(volume); } private void LoadVolumeSettings() { float previousMusicVolume = musicVolume; masterVolume = PlayerPrefs.GetFloat("MasterVolume", 1f); musicVolume = PlayerPrefs.GetFloat("MusicVolume", 1f); sfxVolume = PlayerPrefs.GetFloat("SFXVolume", 1f); Debug.Log($"AudioManager: LoadVolumeSettings - Previous: {previousMusicVolume}, Loaded: {musicVolume}"); Debug.Log($"AudioManager: PlayerPrefs MusicVolume key exists: {PlayerPrefs.HasKey("MusicVolume")}"); } private void ApplyVolumeSettings() { ApplyMusicVolume(); ApplySFXVolume(); } private void ApplyMusicVolume() { if (musicSource != null) { musicSource.volume = masterVolume * musicVolume; } } private void ApplySFXVolume() { if (sfxSource != null) { sfxSource.volume = masterVolume * sfxVolume; } } // Method to play sound effects public void PlaySFX(AudioClip clip, float volumeScale = 1f) { if (sfxSource != null && clip != null) { sfxSource.PlayOneShot(clip, volumeScale * sfxVolume * masterVolume); } } // Method to change background music public void PlayMusic(AudioClip musicClip, bool loop = true) { if (musicSource != null && musicClip != null) { musicSource.clip = musicClip; musicSource.loop = loop; musicSource.Play(); } } // Method to stop music public void StopMusic() { if (musicSource != null) { musicSource.Stop(); isPlaying = false; } } // MUSIC LIBRARY METHODS void InitializeMusicLibrary() { if (musicLibrary.Length == 0) { Debug.LogWarning("AudioManager: No music tracks found in musicLibrary! Please assign your 7 music files."); return; } // Create shuffled playlist if shuffle is enabled if (shuffleMusic) { CreateShuffledPlaylist(); } Debug.Log($"AudioManager: Music library initialized with {musicLibrary.Length} tracks. Shuffle: {shuffleMusic}"); } void CreateShuffledPlaylist() { shuffledIndices = new List(); for (int i = 0; i < musicLibrary.Length; i++) { shuffledIndices.Add(i); } // Fisher-Yates shuffle algorithm for (int i = shuffledIndices.Count - 1; i > 0; i--) { int randomIndex = Random.Range(0, i + 1); int temp = shuffledIndices[i]; shuffledIndices[i] = shuffledIndices[randomIndex]; shuffledIndices[randomIndex] = temp; } shufflePosition = 0; } public void StartPlayingMusic() { if (musicLibrary.Length == 0 || musicSource == null) return; isPlaying = true; PlayCurrentTrack(); // Start checking for track end StartCoroutine(TrackEndChecker()); } void PlayCurrentTrack() { if (musicLibrary.Length == 0) return; int trackIndex = GetCurrentTrackIndex(); if (trackIndex >= 0 && trackIndex < musicLibrary.Length) { AudioClip trackToPlay = musicLibrary[trackIndex]; if (trackToPlay != null) { if (isFading) { StartCoroutine(FadeToNewTrack(trackToPlay)); } else { musicSource.clip = trackToPlay; // FIXED: Use the current volume settings instead of hardcoded values musicSource.volume = musicVolume * masterVolume; musicSource.loop = false; // We handle looping manually musicSource.Play(); } Debug.Log($"AudioManager: Now playing track {trackIndex + 1}/{musicLibrary.Length}: {trackToPlay.name} at volume {musicVolume * masterVolume}"); } } } int GetCurrentTrackIndex() { if (shuffleMusic && shuffledIndices != null && shuffledIndices.Count > 0) { return shuffledIndices[shufflePosition]; } else { return currentTrackIndex; } } IEnumerator TrackEndChecker() { while (isPlaying) { yield return new WaitForSeconds(0.5f); // Check every half second if (musicSource != null && !musicSource.isPlaying && !isFading) { // Track ended, play next PlayNextTrack(); } } } public void PlayNextTrack() { if (musicLibrary.Length <= 1) return; if (shuffleMusic) { shufflePosition++; if (shufflePosition >= shuffledIndices.Count) { if (loopPlaylist) { CreateShuffledPlaylist(); // Create new shuffle order } else { StopMusic(); return; } } } else { currentTrackIndex++; if (currentTrackIndex >= musicLibrary.Length) { if (loopPlaylist) { currentTrackIndex = 0; } else { StopMusic(); return; } } } PlayCurrentTrack(); } public void PlayPreviousTrack() { if (musicLibrary.Length <= 1) return; if (shuffleMusic) { shufflePosition--; if (shufflePosition < 0) { shufflePosition = shuffledIndices.Count - 1; } } else { currentTrackIndex--; if (currentTrackIndex < 0) { currentTrackIndex = musicLibrary.Length - 1; } } PlayCurrentTrack(); } IEnumerator FadeToNewTrack(AudioClip newTrack) { isFading = true; float startVolume = musicSource.volume; // Fade out current track float fadeTimer = 0; while (fadeTimer < fadeDuration / 2) { fadeTimer += Time.deltaTime; musicSource.volume = Mathf.Lerp(startVolume, 0, fadeTimer / (fadeDuration / 2)); yield return null; } // Change track musicSource.clip = newTrack; musicSource.Play(); // Fade in new track fadeTimer = 0; float targetVolume = musicVolume * masterVolume; while (fadeTimer < fadeDuration / 2) { fadeTimer += Time.deltaTime; musicSource.volume = Mathf.Lerp(0, targetVolume, fadeTimer / (fadeDuration / 2)); yield return null; } musicSource.volume = targetVolume; isFading = false; } // Public methods for UI controls public void ToggleShuffle() { shuffleMusic = !shuffleMusic; if (shuffleMusic) { CreateShuffledPlaylist(); } Debug.Log($"AudioManager: Shuffle {(shuffleMusic ? "enabled" : "disabled")}"); } public void TogglePlayPause() { if (musicSource != null) { if (musicSource.isPlaying) { musicSource.Pause(); isPlaying = false; } else { musicSource.UnPause(); isPlaying = true; StartCoroutine(TrackEndChecker()); } } } // Get current track info for UI display public string GetCurrentTrackName() { int trackIndex = GetCurrentTrackIndex(); if (trackIndex >= 0 && trackIndex < musicLibrary.Length && musicLibrary[trackIndex] != null) { return musicLibrary[trackIndex].name; } return "No Track"; } public int GetCurrentTrackNumber() { return GetCurrentTrackIndex() + 1; } public int GetTotalTracks() { return musicLibrary.Length; } // Method to pause/unpause music public void PauseMusic(bool pause) { if (musicSource != null) { if (pause) musicSource.Pause(); else musicSource.UnPause(); } } }