Created
September 26, 2024 05:11
-
-
Save Ddemon26/cc596fbc816baf934db4e361ddcdee97 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.Pool; | |
namespace TCS.TestSystems.AudioManager { | |
// AudioEvent class | |
public class AudioEvent { | |
public AudioClip Clip { get; } | |
public float Volume { get; set; } = 1f; | |
public float Pitch { get; set; } = 1f; | |
public bool Loop { get; set; } = false; | |
public float StereoPan { get; set; } = 0f; | |
public float SpatialBlend { get; set; } = 0f; | |
public float FadeInDuration { get; set; } = 0f; | |
public float FadeOutDuration { get; set; } = 0f; | |
public Vector3? Position { get; set; } = null; | |
public AudioEvent(AudioClip clip) { | |
Clip = clip ?? throw new ArgumentNullException(nameof(clip)); | |
} | |
} | |
// SoundInstance class | |
public class SoundInstance { | |
public AudioEvent AudioEvent { get; } | |
public AudioSource AudioSource { get; } | |
public bool IsPlaying => AudioSource != null && AudioSource.isPlaying; | |
public event Action<SoundInstance> OnFinished; | |
private Coroutine fadeCoroutine; | |
private float fadeInDuration; | |
private float fadeOutDuration; | |
public SoundInstance(AudioEvent audioEvent, AudioSource audioSource) { | |
AudioEvent = audioEvent; | |
AudioSource = audioSource; | |
fadeInDuration = AudioEvent.FadeInDuration; | |
fadeOutDuration = AudioEvent.FadeOutDuration; | |
ConfigureAudioSource(); | |
} | |
private void ConfigureAudioSource() { | |
if (AudioEvent.Position.HasValue) { | |
AudioSource.transform.position = AudioEvent.Position.Value; | |
AudioSource.spatialBlend = 1f; | |
} else { | |
AudioSource.spatialBlend = AudioEvent.SpatialBlend; | |
} | |
AudioSource.clip = AudioEvent.Clip; | |
AudioSource.volume = AudioEvent.Volume; | |
AudioSource.pitch = AudioEvent.Pitch; | |
AudioSource.loop = AudioEvent.Loop; | |
AudioSource.panStereo = AudioEvent.StereoPan; | |
// Additional configurations | |
if (fadeInDuration > 0f) { | |
AudioSource.volume = 0f; | |
fadeCoroutine = AudioManager.Instance.StartCoroutine(FadeIn()); | |
} | |
AudioSource.Play(); | |
if (!AudioEvent.Loop) { | |
AudioManager.Instance.StartCoroutine(CheckIfFinished()); | |
} | |
} | |
private IEnumerator FadeIn() { | |
float time = 0f; | |
while (time < fadeInDuration) { | |
time += Time.deltaTime; | |
AudioSource.volume = Mathf.Lerp(0f, AudioEvent.Volume, time / fadeInDuration); | |
yield return null; | |
} | |
AudioSource.volume = AudioEvent.Volume; | |
} | |
private IEnumerator FadeOutAndStop() { | |
float startVolume = AudioSource.volume; | |
float time = 0f; | |
while (time < fadeOutDuration) { | |
time += Time.deltaTime; | |
AudioSource.volume = Mathf.Lerp(startVolume, 0f, time / fadeOutDuration); | |
yield return null; | |
} | |
AudioSource.volume = 0f; | |
StopImmediate(); | |
} | |
private void StopImmediate() { | |
if (fadeCoroutine != null) { | |
AudioManager.Instance.StopCoroutine(fadeCoroutine); | |
} | |
AudioSource.Stop(); | |
OnFinished?.Invoke(this); | |
} | |
public void Stop() { | |
if (fadeOutDuration > 0f) { | |
fadeCoroutine = AudioManager.Instance.StartCoroutine(FadeOutAndStop()); | |
} else { | |
StopImmediate(); | |
} | |
} | |
private IEnumerator CheckIfFinished() { | |
yield return new WaitUntil(() => !AudioSource.isPlaying); | |
OnFinished?.Invoke(this); | |
} | |
public void FadeOutAndStop(float duration) { | |
fadeOutDuration = duration; | |
fadeCoroutine = AudioManager.Instance.StartCoroutine(FadeOutAndStop()); | |
} | |
} | |
// AudioManager class | |
public class AudioManager : MonoBehaviour { | |
private static AudioManager s_instance; | |
public static AudioManager Instance { | |
get { | |
if (s_instance == null) { | |
var obj = new GameObject("AudioManager"); | |
s_instance = obj.AddComponent<AudioManager>(); | |
} | |
return s_instance; | |
} | |
} | |
private AudioPooler m_audioSourcePool; | |
private AudioSource m_musicSource; | |
private List<SoundInstance> m_activeSounds = new List<SoundInstance>(); | |
void Awake() { | |
if (s_instance == null) { | |
s_instance = this; | |
DontDestroyOnLoad(gameObject); | |
m_audioSourcePool = new AudioPooler(this); | |
InitializeMusicSource(); | |
} else if (s_instance != this) { | |
Destroy(gameObject); | |
} | |
} | |
void InitializeMusicSource() { | |
m_musicSource = gameObject.AddComponent<AudioSource>(); | |
m_musicSource.loop = true; | |
} | |
public SoundInstance PlaySound(AudioEvent audioEvent) { | |
if (audioEvent == null || audioEvent.Clip == null) { | |
Debug.LogError("Invalid AudioEvent or AudioClip."); | |
return null; | |
} | |
var audioSource = m_audioSourcePool.Get(); | |
var soundInstance = new SoundInstance(audioEvent, audioSource); | |
soundInstance.OnFinished += HandleSoundFinished; | |
m_activeSounds.Add(soundInstance); | |
return soundInstance; | |
} | |
public void StopSound(SoundInstance soundInstance) { | |
if (soundInstance != null) { | |
soundInstance.Stop(); | |
} | |
} | |
private void HandleSoundFinished(SoundInstance soundInstance) { | |
soundInstance.OnFinished -= HandleSoundFinished; | |
m_activeSounds.Remove(soundInstance); | |
m_audioSourcePool.Release(soundInstance.AudioSource); | |
} | |
public void StopSoundByClip(AudioClip clip) { | |
var soundsToStop = m_activeSounds.FindAll(s => s.AudioEvent.Clip == clip); | |
foreach (var sound in soundsToStop) { | |
sound.Stop(); | |
} | |
} | |
public void PlayMusic(AudioEvent audioEvent) { | |
if (audioEvent == null || audioEvent.Clip == null) { | |
Debug.LogError("Invalid AudioEvent or AudioClip."); | |
return; | |
} | |
m_musicSource.clip = audioEvent.Clip; | |
m_musicSource.volume = audioEvent.Volume; | |
m_musicSource.pitch = audioEvent.Pitch; | |
m_musicSource.loop = audioEvent.Loop; | |
m_musicSource.panStereo = audioEvent.StereoPan; | |
// Additional configurations | |
m_musicSource.Play(); | |
} | |
public void StopMusic() { | |
m_musicSource.Stop(); | |
} | |
public void StopAllSounds() { | |
foreach (var soundInstance in m_activeSounds) { | |
soundInstance.Stop(); | |
} | |
m_activeSounds.Clear(); | |
m_musicSource.Stop(); | |
} | |
} | |
// AudioPooler class | |
public class AudioPooler { | |
private ObjectPool<AudioSource> m_audioSourcePool; | |
private readonly int m_initialPoolSize = 10; | |
private readonly int m_maxPoolSize = 100; | |
private readonly AudioManager m_audioManager; | |
public AudioPooler(AudioManager audioManager, int initialPoolSize = 10, int maxPoolSize = 100) { | |
m_audioManager = audioManager; | |
m_initialPoolSize = initialPoolSize; | |
m_maxPoolSize = maxPoolSize; | |
InitializePool(); | |
} | |
void InitializePool() { | |
m_audioSourcePool = new ObjectPool<AudioSource>( | |
CreatePooledItem, | |
OnTakeFromPool, | |
OnReturnedToPool, | |
OnDestroyPoolObject, | |
true, | |
m_initialPoolSize, | |
m_maxPoolSize | |
); | |
} | |
AudioSource CreatePooledItem() { | |
var go = new GameObject("PooledAudioSource"); | |
go.transform.SetParent(m_audioManager.transform); | |
return go.AddComponent<AudioSource>(); | |
} | |
void OnReturnedToPool(AudioSource audioSource) { | |
audioSource.Stop(); | |
audioSource.clip = null; | |
audioSource.gameObject.SetActive(false); | |
} | |
void OnTakeFromPool(AudioSource audioSource) { | |
audioSource.gameObject.SetActive(true); | |
} | |
void OnDestroyPoolObject(AudioSource audioSource) { | |
GameObject.Destroy(audioSource.gameObject); | |
} | |
public AudioSource Get() { | |
return m_audioSourcePool.Get(); | |
} | |
public void Release(AudioSource source) { | |
m_audioSourcePool.Release(source); | |
} | |
} | |
// Extension methods for easier API usage | |
public static class AudioClipExtensions { | |
public static SoundInstance PlaySound(this AudioClip clip, float volume = 1f, float pitch = 1f, bool loop = false, float fadeInDuration = 0f, float fadeOutDuration = 0f) { | |
var audioEvent = new AudioEvent(clip) { | |
Volume = volume, | |
Pitch = pitch, | |
Loop = loop, | |
FadeInDuration = fadeInDuration, | |
FadeOutDuration = fadeOutDuration | |
}; | |
return AudioManager.Instance.PlaySound(audioEvent); | |
} | |
public static void StopSound(this AudioClip clip) { | |
AudioManager.Instance.StopSoundByClip(clip); | |
} | |
public static SoundInstance PlaySpatialSound(this AudioClip clip, Vector3 position, float volume = 1f, float pitch = 1f, bool loop = false, float fadeInDuration = 0f, float fadeOutDuration = 0f) { | |
var audioEvent = new AudioEvent(clip) { | |
Volume = volume, | |
Pitch = pitch, | |
Loop = loop, | |
FadeInDuration = fadeInDuration, | |
FadeOutDuration = fadeOutDuration, | |
Position = position, | |
SpatialBlend = 1f | |
}; | |
return AudioManager.Instance.PlaySound(audioEvent); | |
} | |
public static void PlayMusic(this AudioClip clip, float volume = 1f, float pitch = 1f, bool loop = true) { | |
var audioEvent = new AudioEvent(clip) { | |
Volume = volume, | |
Pitch = pitch, | |
Loop = loop | |
}; | |
AudioManager.Instance.PlayMusic(audioEvent); | |
} | |
} | |
// PlayerController class | |
public class PlayerController : MonoBehaviour { | |
public AudioClip m_jumpClip; | |
public AudioClip m_walkClip; | |
public AudioClip m_footstepClip; | |
public AudioClip m_backgroundMusicClip; | |
bool m_isWalking; | |
SoundInstance m_walkSoundInstance; | |
void Update() { | |
HandleJump(); | |
HandleWalk(); | |
HandleFootsteps(); | |
HandleBackgroundMusic(); | |
HandleSpatialSounds(); | |
} | |
void HandleJump() { | |
if (Input.GetKeyDown(KeyCode.Space)) { | |
Debug.Log("Player jumped"); | |
m_jumpClip.PlaySound(volume: 0.8f, pitch: 1.2f); | |
} | |
if (Input.GetKeyDown(KeyCode.J)) { | |
Debug.Log("Stop jump sound"); | |
m_jumpClip.StopSound(); | |
} | |
} | |
void HandleWalk() { | |
if (IsWalking()) { | |
if (!m_isWalking) { | |
Debug.Log("Player started walking"); | |
m_walkSoundInstance = m_walkClip.PlaySound(volume: CalculateVolumeBasedOnSpeed(), loop: true); | |
m_isWalking = true; | |
} | |
} else { | |
if (m_isWalking) { | |
Debug.Log("Player stopped walking"); | |
if (m_walkSoundInstance != null) { | |
m_walkSoundInstance.Stop(); | |
} | |
m_isWalking = false; | |
} | |
} | |
} | |
void HandleFootsteps() { | |
if (Input.GetKeyDown(KeyCode.F)) { | |
Debug.Log("Playing footstep sound with random pitch"); | |
m_footstepClip.PlaySound(pitch: UnityEngine.Random.Range(0.9f, 1.1f)); | |
} | |
if (Input.GetKeyDown(KeyCode.S)) { | |
Debug.Log("Stop footstep sound"); | |
m_footstepClip.StopSound(); | |
} | |
} | |
void HandleBackgroundMusic() { | |
if (Input.GetKeyDown(KeyCode.M)) { | |
Debug.Log("Playing background music"); | |
m_backgroundMusicClip.PlayMusic(volume: 0.6f, loop: true); | |
} | |
if (Input.GetKeyDown(KeyCode.N)) { | |
Debug.Log("Stopping background music"); | |
AudioManager.Instance.StopMusic(); | |
} | |
} | |
void HandleSpatialSounds() { | |
if (Input.GetKeyDown(KeyCode.G)) { | |
Debug.Log("Playing spatial sound at a specific position"); | |
var soundPosition = transform.position; | |
m_footstepClip.PlaySpatialSound(soundPosition, volume: 1f); | |
} | |
} | |
bool IsWalking() { | |
return Input.GetKey(KeyCode.W); | |
} | |
float CalculateVolumeBasedOnSpeed() { | |
// Placeholder: replace with actual logic | |
return 1f; | |
} | |
void OnGUI() { | |
GUI.Label(new Rect(10, 10, 200, 20), "Press Space to jump"); | |
GUI.Label(new Rect(10, 30, 200, 20), "Press J to stop jump sound"); | |
GUI.Label(new Rect(10, 50, 200, 20), "Press W to walk"); | |
GUI.Label(new Rect(10, 70, 200, 20), "Press F to play footstep sound"); | |
GUI.Label(new Rect(10, 90, 200, 20), "Press S to stop footstep sound"); | |
GUI.Label(new Rect(10, 110, 200, 20), "Press G to play spatial sound"); | |
GUI.Label(new Rect(10, 130, 200, 20), "Press M to play background music"); | |
GUI.Label(new Rect(10, 150, 200, 20), "Press N to stop background music"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment