Files
CourierOld/Game/CourierOld/Assets/Code/Audio/AudioSourcePool.cs
T
2025-11-27 21:30:00 +03:00

121 lines
5.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using Code.Configs;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Pool;
using Object = UnityEngine.Object;
namespace Code.Audio
{
public class AudioSourcePool
{
// The pool holds plain GameObjects (you can swap this for any component type).
private IObjectPool<AudioSource> _pool;
private GameObject _sourcePrefab;
private Dictionary<AudioSourceType, AudioSourceSettingsConfig> _settings;
public AudioSourcePool(Dictionary<AudioSourceType, AudioSourceSettingsConfig> settings) => _settings = settings;
public void Initialize(GameObject sourcePrefab)
{
_sourcePrefab = sourcePrefab;
// Create a pool with the four core callbacks.
_pool = new ObjectPool<AudioSource>(
createFunc: CreateItem,
// actionOnGet: OnGet,
actionOnRelease: OnRelease,
actionOnDestroy: OnDestroyItem,
collectionCheck: true, // helps catch double-release mistakes
defaultCapacity: 10,
maxSize: 20
);
}
// Creates a new pooled GameObject the first time (and whenever the pool needs more).
private AudioSource CreateItem()
{
AudioSource audioSource = Object.Instantiate(_sourcePrefab).GetComponent<AudioSource>();
audioSource.name = "PooledAudioSource";
Object.DontDestroyOnLoad(audioSource);
return audioSource;
}
// Called when an item is taken from the pool.
private void OnGet(AudioSource source)
{
//source.gameObject.SetActive(true);
}
// Called when an item is returned to the pool.
private void OnRelease(AudioSource source)
{
source.Stop();
//source.gameObject.SetActive(false);
}
// Called when the pool decides to destroy an item (e.g., above max size).
private void OnDestroyItem(AudioSource source)
{
Object.Destroy(source.gameObject);
}
public async UniTaskVoid PlayOneShot(AudioClip clip, Vector3 position, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
{
AudioSource source = _pool.Get();
source.PlayOneShot(clip);
source.spatialBlend = _settings[audioSourceType].spatialBlend;
source.transform.position = position;
source.outputAudioMixerGroup = audioMixerGroup;
await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
onComplete?.Invoke();
_pool.Release(source);
}
public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
{
AudioSource source = _pool.Get();
source.PlayOneShot(clip);
source.spatialBlend = _settings[audioSourceType].spatialBlend;
source.outputAudioMixerGroup = audioMixerGroup;
await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
onComplete?.Invoke();
_pool.Release(source);
}
public async UniTaskVoid PlayOneShot(AudioSource audioSource, AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
{
audioSource.PlayOneShot(clip);
audioSource.spatialBlend = _settings[audioSourceType].spatialBlend;
audioSource.outputAudioMixerGroup = audioMixerGroup;
// TODO Потом сделать. Можно с cancellation, но сейчас лень. Ну правда
await UniTask.WaitUntilValueChanged(audioSource, x => x.isPlaying);
if (!audioSource) return;
_pool.Release(audioSource);
onComplete?.Invoke();
}
public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, CancellationTokenSource cancellationToken, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
{
AudioSource source = _pool.Get();
source.PlayOneShot(clip);
source.spatialBlend = _settings[audioSourceType].spatialBlend;
source.outputAudioMixerGroup = audioMixerGroup;
var (isCanceled, _) = await UniTask.WaitUntilValueChanged(source, x => x.isPlaying, cancellationToken: cancellationToken.Token).SuppressCancellationThrow();
_pool.Release(source);
if(!isCanceled) onComplete?.Invoke();
else cancellationToken.Dispose();
}
public AudioSource GetSource() => _pool.Get();
public void ReleaseSource(AudioSource source) => _pool.Release(source);
}
}