570 lines
16 KiB
C#
570 lines
16 KiB
C#
|
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<int> 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<Slider>(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<Slider>(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<int>();
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|