Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / Managers / AudioManager.cs
  1. using Eflatun.SceneReference;
  2. using MyCollections.Managers;
  3. using MyCollections.SceneManagement;
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. using UnityEngine.Audio;
  9. using UnityEngine.SceneManagement;
  10. public class AudioManager : MonoBehaviour
  11. {
  12. // Singleton instance
  13. public static AudioManager Instance { get; private set; }
  14. //Audio Mixer settings
  15. [Header("Mixer Settings")]
  16. public AudioMixer audioMixer; // Reference to AudioMixer for volume control
  17. public AudioMixerGroup musicMixerGroup;
  18. public AudioMixerGroup sfxMixerGroup;
  19. //Audio sources
  20. [Header("Audio Sources")]
  21. [SerializeField] private AudioSource musicSource; // Audio source for music
  22. [SerializeField] private AudioSource sfxSource; // Audio source for SFX
  23. [Header("Audio Clips")]
  24. public List<Sound> sounds = new List<Sound>(); // Array of sounds
  25. private Coroutine musicTransitionCoroutine;
  26. private GameStateManager gameStateManager;
  27. private bool isTransitioning = false;
  28. // Music fade duration
  29. [Header("Transition Settings")]
  30. public float musicTransitionTime = 2f;
  31. void Awake()
  32. {
  33. if (Instance != null && Instance != this)
  34. {
  35. Destroy(gameObject);
  36. }
  37. else
  38. {
  39. Instance = this;
  40. DontDestroyOnLoad(gameObject); // Persist across scenes
  41. }
  42. if (musicSource == null)
  43. {
  44. //Audio Source for the music
  45. //Only one is necessary
  46. musicSource = gameObject.AddComponent<AudioSource>();
  47. musicSource.outputAudioMixerGroup = musicMixerGroup;
  48. }
  49. InitializeSounds();
  50. //SceneLoader
  51. }
  52. private void Start()
  53. {
  54. gameStateManager = GameStateManager.Instance;
  55. gameStateManager.OnGameStateChange += PlayMusicOnStateChange;
  56. }
  57. // Control volume via the AudioMixer
  58. public void SetVolume(string parameter, float value)
  59. {
  60. audioMixer.SetFloat(parameter, Mathf.Log10(value) * 20); // Convert linear slider value to logarithmic
  61. }
  62. public void InitializeSounds()
  63. {
  64. // Initialize each sound with its settings
  65. foreach (Sound sound in sounds)
  66. {
  67. sound.source = sound.audioMixerGroup == Sound.AudioType.SFX ? gameObject.AddComponent<AudioSource>() : musicSource;
  68. sound.source.clip = sound.clip;
  69. sound.source.volume = sound.volume;
  70. sound.source.pitch = sound.pitch;
  71. sound.source.loop = sound.loop;
  72. sound.source.outputAudioMixerGroup = sound.audioMixerGroup == Sound.AudioType.Music ? musicMixerGroup : sfxMixerGroup;
  73. }
  74. }
  75. private void Update()
  76. {
  77. if (!musicSource.isPlaying && !isTransitioning)
  78. {
  79. foreach (Sound sound in sounds)
  80. {
  81. if (sound.audioMixerGroup == Sound.AudioType.Music)
  82. {
  83. Debug.Log("I FOUND A SOUND TO PLAY");
  84. PlayMusic(sound.name);
  85. break;
  86. }
  87. }
  88. }
  89. }
  90. public void Play(AudioSource source, string name)
  91. {
  92. Sound s = sounds.Find(sound => sound.name == name);
  93. if (s == null)
  94. {
  95. Debug.LogWarning($"Sound: {name} not found!");
  96. return;
  97. }
  98. source.clip = s.clip;
  99. source.Play();
  100. }
  101. public void Play(AudioSource source, AudioClip clip)
  102. {
  103. source.clip = clip;
  104. source.Play();
  105. }
  106. //Play SFX sound
  107. public void Play(string name)
  108. {
  109. Sound s = sounds.Find(sound => sound.name == name);
  110. if (s == null)
  111. {
  112. Debug.LogWarning($"Sound: {name} not found!");
  113. return;
  114. }
  115. s.source.Play();
  116. }
  117. public void PlayMusic(string name)
  118. {
  119. Sound s = sounds.Find(sound => sound.name == name);
  120. if (s == null)
  121. {
  122. Debug.LogWarning($"Music: {name} not found!");
  123. return;
  124. }
  125. musicSource.clip = s.clip;
  126. musicSource.Play();
  127. }
  128. public void PlayMusic(Sound.AudioTag tag)
  129. {
  130. Sound s = sounds.Find(sound => sound.audioTag == tag);
  131. if (s == null)
  132. {
  133. Debug.LogWarning($"Music: {tag} not found!");
  134. return;
  135. }
  136. // If already transitioning or playing the same music, don't restart the transition
  137. if (musicSource.isPlaying && musicSource.clip == s.clip)
  138. {
  139. return;
  140. }
  141. PlayTransitionMusic(tag);
  142. }
  143. private void PlayMusicOnStateChange(GameState newState)
  144. {
  145. switch (newState)
  146. {
  147. case(GameState.Combat):
  148. PlayMusic(Sound.AudioTag.EnterCombat);
  149. break;
  150. case (GameState.Normal):
  151. PlayMusic(Sound.AudioTag.Calm);
  152. break;
  153. case (GameState.Loading):
  154. Stop(musicSource);
  155. break;
  156. }
  157. }
  158. //Plays music
  159. public void PlayTransitionMusic(Sound.AudioTag tag)
  160. {
  161. Sound s = sounds.Find(sound => sound.audioTag == tag);
  162. if (s == null)
  163. {
  164. Debug.LogWarning($"Music with tag {tag} not found!");
  165. return;
  166. }
  167. if (musicTransitionCoroutine != null)
  168. StopCoroutine(musicTransitionCoroutine);
  169. // Transition to the new music
  170. musicTransitionCoroutine = StartCoroutine(TransitionMusic(s));
  171. }
  172. //Stop sound
  173. public void Stop(string name)
  174. {
  175. Sound s = sounds.Find(sound => sound.name == name);
  176. if (s == null)
  177. {
  178. Debug.LogWarning($"Sound: {name} not found!");
  179. return;
  180. }
  181. s.source.Stop();
  182. }
  183. public void Stop(AudioSource source)
  184. {
  185. Sound s = sounds.Find(sound => sound.name == name);
  186. if (s == null)
  187. {
  188. Debug.LogWarning($"Sound: {name} not found!");
  189. return;
  190. }
  191. source.Stop();
  192. }
  193. // Coroutine to handle smooth transition between music tracks
  194. private IEnumerator TransitionMusic(Sound newMusic)
  195. {
  196. isTransitioning = true;
  197. // Slight delay to give time for audio state to update
  198. yield return new WaitForSeconds(0.1f);
  199. Debug.Log("Is Music Playing: " + musicSource.isPlaying);
  200. // Fade out the current music if any is playing
  201. if (musicSource.isPlaying)
  202. {
  203. Debug.Log("Fading out current music...");
  204. yield return StartCoroutine(FadeOut(musicSource, musicTransitionTime));
  205. }
  206. // Set the new music clip and play it
  207. Debug.Log("Fading in new music...");
  208. musicSource.clip = newMusic.clip;
  209. musicSource.Play();
  210. // Fade in the new music
  211. yield return StartCoroutine(FadeIn(musicSource, musicTransitionTime));
  212. isTransitioning = false;
  213. }
  214. //Smoothly fades Out a music
  215. private IEnumerator FadeOut(AudioSource audioSource, float duration)
  216. {
  217. float startVolume = audioSource.volume;
  218. float targetVolume = 0f;
  219. Debug.Log("Starting fade out");
  220. for (float t = 0; t < duration; t += Time.deltaTime)
  221. {
  222. audioSource.volume = Mathf.Lerp(startVolume, targetVolume, t / duration);
  223. yield return null;
  224. }
  225. audioSource.volume = targetVolume;
  226. audioSource.Stop();
  227. Debug.Log("Stop fade out");
  228. }
  229. //Smoothly fades In a music
  230. private IEnumerator FadeIn(AudioSource audioSource, float duration)
  231. {
  232. float targetVolume = 1f;
  233. audioSource.volume = 0;
  234. audioSource.Play();
  235. for (float t = 0; t < duration; t += Time.deltaTime)
  236. {
  237. audioSource.volume = Mathf.Lerp(0, targetVolume, t / duration);
  238. yield return null;
  239. }
  240. }
  241. //Load sounds when a scene or a gorup of scenes is loaded
  242. public void LoadSounds(Sound[] sceneSounds) => sounds.AddRange(sceneSounds);
  243. //Unloads sound
  244. //If a scene is unloaded, there's no need to keep sounds in memory
  245. public void UnloadSounds(Sound[] sceneSounds)
  246. {
  247. foreach (Sound sound in sceneSounds)
  248. {
  249. Sound s = sounds.Find(s => s.name == sound.name);
  250. if (s != null)
  251. sounds.Remove(s);
  252. }
  253. }
  254. }
  255. [Serializable]
  256. public class Sound
  257. {
  258. public enum AudioType { Music, SFX } // Separate music and sound effects
  259. public enum AudioTag { Calm, EnterCombat, ExitCombat}
  260. public string name;
  261. public AudioClip clip;
  262. public AudioType audioMixerGroup;
  263. public AudioTag audioTag;
  264. [Range(0f, 1f)] public float volume = 0.7f;
  265. [Range(0.1f, 3f)] public float pitch = 1f;
  266. public bool loop;
  267. public AudioSource source;
  268. }