Space-Smash-Out/Assets/Scripts/Managers/AudioManager.cs
Jakob Feldmann 9a9a9c8b21 feat: music which has the same tag(different id) can now be randomly played, new tracks
You can say play a "menu_music" and a random track tagged as such will be played.
2024-05-05 17:50:04 +02:00

264 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using log4net;
using Unity.Burst.Intrinsics;
using UnityEngine;
namespace Managers
{
public class AudioManager : MonoBehaviour
{
private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static AudioManager G { get; private set; }
[HideInInspector]
public AudioLibrary audioLibrary;
private Dictionary<ManageableAudio, GameObject> audioDictionary =
new Dictionary<ManageableAudio, GameObject>();
public delegate void OnAudioEffectBroadcast(AudioEffectBroadCastEventArgs args);
public event OnAudioEffectBroadcast AudioEffectBroadcasted;
// Start is called before the first frame update
void Awake()
{
G = this;
Log.Info("Awake");
if (gameObject.TryGetComponent(out AudioLibrary al))
{
audioLibrary = al;
}
else
{
Log.Warn("There is no audio library component in the AudioManager. There will be no sound.");
}
}
void Start()
{
if (audioLibrary == null)
{
return;
}
audioDictionary = ReadLibrary(audioLibrary);
}
/// <summary>
/// Instantiates a sound from the library which will be used for global and
/// scene independent sound.
/// </summary>
/// <param name="prefabName">Name of the sound prefab</param>
/// <param name="dependsOnScene">Should the audio be destroyed, when the calling scene is destroyed?</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetGlobalSoundByName(string prefabName, bool dependsOnScene = false)
{
return GetGlobalSound(null, -1, dependsOnScene, SearchSound(null, -1, prefabName));
}
/// <summary>
/// Instantiates a sound from the library which will be used for local, spatial and
/// scene dependent sound. It reparents the object(AudioSource + ManageableAudio component),
/// to the provided transform.
/// </summary>
/// <param name="prefabName">Name of the sound prefab</param>
/// <param name="transform">Transform which will parent the sound object.</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetLocalSoundByName(string prefabName, Transform transform)
{
return GetLocalSound(null, -1, transform, SearchSound(null, -1, prefabName));
}
/// <summary>
/// Instantiates a random sound, chosen from a tag group,
/// from the library which will be used for global and
/// scene independent sound.
/// </summary>
/// <param name="audioTag">Tag group which will be randomly chosen from</param>
/// <param name="dependsOnScene">Should the audio be destroyed, when the calling scene is destroyed?</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetGlobalSoundRandom(string audioTag, bool dependsOnScene = false)
{
return GetGlobalSound(null, -1, dependsOnScene, SearchSoundRandom(audioTag));
}
/// <summary>
/// Instantiates a random sound, chosen from a tag group,
/// from the library which will be used for local, spatial and
/// scene dependent sound. It reparents the object(AudioSource + ManageableAudio component),
/// to the provided transform.
/// </summary>
/// <param name="audioTag">Tag group which will be randomly chosen from</param>
/// <param name="transform">Transform which will parent the sound object</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetLocalSoundRandom(string audioTag, Transform transform)
{
return GetLocalSound(null, -1, transform, SearchSoundRandom(audioTag));
}
/// <summary>
/// Instantiates a sound from the library which will be used for global sound.
/// The ManageableAudio object is instantiated in the currently active scene,
/// when dependsOnScene is true!
/// </summary>
/// <param name="audioTag">Tag of the sound</param>
/// <param name="id">ID of the sound</param>
/// <param name="dependsOnScene">Should the audio be destroyed, when the calling scene is destroyed?</param>
/// <param name="go">Optionally provide the sound GameObject directly.</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetGlobalSound(string audioTag, int id, bool dependsOnScene = false,
GameObject go = null)
{
GameObject sound;
if (go == null)
{
sound = SearchSound(audioTag, id);
}
else
{
sound = go;
}
if (sound == null)
{
Log.Warn($"Requested sound: {audioTag}_{id} was not in the audio library.");
return null;
}
sound = Instantiate(sound);
if (!dependsOnScene)
sound.transform.SetParent(gameObject.transform);
if (sound.TryGetComponent(out ManageableAudio ma))
{
return ma;
}
else
{
Log.Warn($"Prefab for sound: {audioTag}_{id} contained no ManageableAudio component");
return null;
}
}
/// <summary>
/// Instantiates a sound from the library which will be used for local, spatial and
/// scene dependent sound. It reparents the object(AudioSource + ManageableAudio component),
/// to the provided transform.
/// </summary>
/// <param name="audioTag">Tag of the sound</param>
/// <param name="id">ID of the sound</param>
/// <param name="newParent">Transform which will parent the sound object.</param>
/// <param name="go"> Optionally provide the sound GameObject directly.</param>
/// <returns>ManageableAudio instance to control the playback with.</returns>
public ManageableAudio GetLocalSound(string audioTag, int id, Transform newParent,
GameObject go = null)
{
GameObject sound;
if (go == null)
{
sound = SearchSound(audioTag, id);
}
else
{
sound = go;
}
if (sound == null)
{
Log.Warn($"Requested sound: {audioTag}_{id} was not in the audio library.");
return null;
}
sound = Instantiate(sound);
sound.transform.SetParent(newParent, false);
if (sound.TryGetComponent(out ManageableAudio ma))
{
return ma;
}
else
{
Log.Warn($"Prefab for sound: {audioTag}_{id} contained no ManageableAudio component");
return null;
}
}
// There are sounds which are scene independent and always global -> will continue playing even if the scene invoking is destroyed
// -"- scene dependent and global -> will play globally but when the scene is destroyed they will be also destroyed
// -"- scene dependent and local -> will play spatially from a object and be destroyed when the scene is destroyed
Dictionary<ManageableAudio, GameObject> ReadLibrary(AudioLibrary al)
{
Dictionary<ManageableAudio, GameObject> audioDictionary =
new Dictionary<ManageableAudio, GameObject>();
foreach (GameObject go in al.audios)
{
if (go.TryGetComponent(out ManageableAudio ma))
{
audioDictionary.Add(ma, go);
}
}
return audioDictionary;
}
private GameObject SearchSoundRandom(string audioTag)
{
try
{
var tagGroup = audioDictionary.Keys.
Where(manageableAudio => manageableAudio.audioTag == audioTag).ToList();
System.Random rnd = new System.Random();
rnd.Next();
int randomIndex = rnd.Next(tagGroup.Count);
return audioDictionary[tagGroup[randomIndex]];
}
catch (Exception e)
{
Log.Error(e.Message);
return null;
}
}
private GameObject SearchSound(string audioTag = null, int id = -1,
string prefabName = null)
{
try
{
if (prefabName == null)
{
return audioDictionary.
Where(manageableAudio => manageableAudio.Key.audioTag == audioTag)?.
First(manageableAudio => manageableAudio.Key.id == id).Value;
}
else
{
return audioDictionary.
First(manageableAudio => manageableAudio.Value.name == prefabName).Value;
}
}
catch (Exception e)
{
Log.Error(e.Message);
return null;
}
}
public void BroadcastAudioEffect(AudioEffects effect, Transform t, bool activate)
{
AudioEffectBroadcasted.Invoke(new AudioEffectBroadCastEventArgs
{
AffectedParent = t,
Effect = effect,
Activate = activate
});
}
}
public class AudioEffectBroadCastEventArgs : EventArgs
{
public Transform AffectedParent { get; set; }
public AudioEffects Effect { get; set; }
public bool Activate { get; set; }
}
}