121 lines
5.0 KiB
C#
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);
|
|
}
|
|
} |