UnityTowerDefense/Assets/_Project/Scripts/Audio/AudioManager.cs

91 lines
3.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Assets/_Project/Scripts/Audio/AudioManager.cs
using System.Collections.Generic;
using UnityEngine;
namespace TD.Audio
{
public class AudioManager : MonoBehaviour
{
[System.Serializable]
public struct CategoryConfig
{
public AudioCategory category;
public int maxVoices;
// NOTE: currently inert. It seeds each pooled AudioSource at init, but every
// Play() call overwrites src.volume with (per-sound volume × SFX slider), so
// this value never reaches the mix. Left as-is rather than "fixed" because
// multiplying it in would halve every existing sound (authored scenes use 0.5).
// Wire it up only alongside a pass to re-level the per-sound volumes.
[Range(0f, 1f)]
public float volume;
}
public static AudioManager Instance { get; private set; }
[SerializeField] private CategoryConfig[] categories;
private Dictionary<AudioCategory, AudioSource[]> pools;
private Dictionary<AudioCategory, int> indices;
private void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
return;
}
Instance = this;
InitializePools();
}
private void OnDestroy()
{
if (Instance == this) Instance = null;
}
private void InitializePools()
{
pools = new Dictionary<AudioCategory, AudioSource[]>();
indices = new Dictionary<AudioCategory, int>();
foreach (var config in categories)
{
var pool = new AudioSource[config.maxVoices];
for (int i = 0; i < config.maxVoices; i++)
{
var src = gameObject.AddComponent<AudioSource>();
src.playOnAwake = false;
src.volume = config.volume;
pool[i] = src;
}
pools[config.category] = pool;
indices[config.category] = 0;
}
}
/// <summary>
/// Plays a one-shot on the given category's voice pool. <paramref name="volume"/> is
/// the per-sound authored level; it's scaled by the player's SFX slider
/// (<see cref="AudioVolumeSettings.SfxScalar"/>) on the way in.
/// </summary>
/// <remarks>
/// The scalar is sampled at play time, so a sound already in flight keeps the volume
/// it started with when the slider moves. Every SFX here is short, so that's
/// imperceptible and avoids having to track live voices.
/// </remarks>
public void Play(AudioClip clip, AudioCategory category, float pitch = 1f, float volume = 1f)
{
if (clip == null) return;
if (!pools.TryGetValue(category, out var pool)) return;
int idx = indices[category];
var src = pool[idx % pool.Length];
src.pitch = pitch;
src.volume = volume * AudioVolumeSettings.SfxScalar;
src.clip = clip;
src.Play();
indices[category] = idx + 1;
}
}
}