2025-03-07 23:32:42 -05:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
2025-04-18 15:54:50 -04:00
|
|
|
using UnityEngine;
|
|
|
|
|
using Game;
|
|
|
|
|
using Music;
|
|
|
|
|
using Player;
|
2025-03-07 23:32:42 -05:00
|
|
|
using UnityEngine.SceneManagement;
|
2025-04-18 15:54:50 -04:00
|
|
|
|
2025-04-16 19:57:54 -04:00
|
|
|
namespace Music
|
|
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Manages the music playlists for the game.
|
|
|
|
|
/// Handles the initialization, playback, and shuffling of music tracks based on the active scene.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class MusicManager : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A singleton instance of the <see cref="MusicManager"/> class.
|
|
|
|
|
/// Ensures only one instance of the MusicManager exists at a time.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static MusicManager Instance;
|
2025-03-07 23:32:42 -05:00
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// A list of playlists available in the game.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public List<Playlist> playlists;
|
2025-03-07 23:32:42 -05:00
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// A dictionary mapping scene names to their corresponding playlists.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Dictionary<string, Playlist> sceneToPlaylist = new Dictionary<string, Playlist>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The prefab used to create audio sources for playing songs.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public GameObject songPrefab;
|
2025-03-07 23:32:42 -05:00
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Ensures only one instance of the MusicManager exists and initializes the scene-to-playlist mapping.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Awake()
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
if (Instance == null)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
Instance = this;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Destroy(this.gameObject);
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
foreach (Playlist playlist in playlists)
|
|
|
|
|
{
|
|
|
|
|
foreach (string scene in playlist.trackScenes)
|
|
|
|
|
{
|
|
|
|
|
sceneToPlaylist.Add(scene, playlist);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-28 13:00:37 -04:00
|
|
|
}
|
2025-03-07 23:32:42 -05:00
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Starts the music playlist for the current active scene.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void StartPlaylist()
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
if (GetActiveSceneNotTitleScreen() == "Player Select") return;
|
|
|
|
|
|
|
|
|
|
StopAllCoroutines();
|
|
|
|
|
foreach (Transform child in transform)
|
|
|
|
|
{
|
|
|
|
|
Destroy(child.gameObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
StartCoroutine(PlayPlaylist(sceneToPlaylist[GetActiveSceneNotTitleScreen()]));
|
|
|
|
|
}
|
|
|
|
|
catch (System.Exception)
|
|
|
|
|
{
|
|
|
|
|
print("No playlist found for this scene: " + GetActiveSceneNotTitleScreen());
|
|
|
|
|
}
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Starts the music playlist for a specific scene.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="scene">The name of the scene for which to start the playlist.</param>
|
|
|
|
|
public void StartPlaylist(string scene)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
if (GetActiveSceneNotTitleScreen() == "Player Select") return;
|
|
|
|
|
|
|
|
|
|
StopAllCoroutines();
|
|
|
|
|
foreach (Transform child in transform)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
Destroy(child.gameObject);
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
|
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
StartCoroutine(PlayPlaylist(sceneToPlaylist[scene]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Plays the specified playlist by shuffling and playing its songs in sequence.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="playlist">The playlist to play.</param>
|
|
|
|
|
/// <returns>An enumerator for the coroutine.</returns>
|
|
|
|
|
private IEnumerator PlayPlaylist(Playlist playlist)
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
// Shuffle the playlist
|
|
|
|
|
List<AudioClip> randomized = new List<AudioClip>(playlist.songs);
|
|
|
|
|
for (int i = 0; i < randomized.Count; i++)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
AudioClip temp = randomized[i];
|
|
|
|
|
int randomIndex = Random.Range(i, randomized.Count);
|
|
|
|
|
randomized[i] = randomized[randomIndex];
|
|
|
|
|
randomized[randomIndex] = temp;
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
2025-04-18 15:54:50 -04:00
|
|
|
|
|
|
|
|
// Play each song in the shuffled playlist
|
|
|
|
|
foreach (AudioClip song in randomized)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
AudioSource songInstance = Instantiate(songPrefab, transform).GetComponent<AudioSource>();
|
|
|
|
|
songInstance.clip = song;
|
|
|
|
|
songInstance.volume = playlist.volume;
|
|
|
|
|
songInstance.Play();
|
|
|
|
|
|
|
|
|
|
if (playlist.shuffleTime > 0f)
|
|
|
|
|
{
|
|
|
|
|
yield return new WaitForSeconds(playlist.shuffleTime);
|
|
|
|
|
float time = 0f;
|
|
|
|
|
while (time < 5f)
|
|
|
|
|
{
|
|
|
|
|
songInstance.volume = playlist.volume * (1 - time / 5f);
|
|
|
|
|
time += Time.deltaTime;
|
|
|
|
|
yield return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
yield return new WaitForSeconds(song.length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Destroy(songInstance.gameObject);
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-18 15:54:50 -04:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the name of the currently active scene, excluding the "Title Screen".
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The name of the active scene, or "Title Screen" if no other scene is active.</returns>
|
|
|
|
|
public static string GetActiveSceneNotTitleScreen()
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
|
2025-03-07 23:32:42 -05:00
|
|
|
{
|
2025-04-18 15:54:50 -04:00
|
|
|
if (SceneManager.GetSceneAt(sceneIndex).name != "Title Screen")
|
|
|
|
|
{
|
|
|
|
|
return SceneManager.GetSceneAt(sceneIndex).name;
|
|
|
|
|
}
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
2025-04-18 15:54:50 -04:00
|
|
|
return "Title Screen";
|
2025-03-07 23:32:42 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-16 19:57:54 -04:00
|
|
|
}
|