RepoTown/Assets/Scripts/AudioManager.cs

570 lines
16 KiB
C#
Raw Normal View History

2025-07-25 15:29:14 +05:00
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();
}
}
}