备份CatanBuilding瘦身独立工程
This commit is contained in:
323
Assets/Scripts/Sound/SoundService.cs
Normal file
323
Assets/Scripts/Sound/SoundService.cs
Normal file
@@ -0,0 +1,323 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Assertions;
|
||||
using asap.core.common;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using System.Threading;
|
||||
using System;
|
||||
using UniRx;
|
||||
|
||||
namespace asap.core
|
||||
{
|
||||
public interface ISoundService
|
||||
{
|
||||
[Inject]
|
||||
public IObjectPoolService poolService { set; }
|
||||
public int MasterVol { get; set; }
|
||||
public int BGMVol { get; set; }
|
||||
public int SFXVol { get; set; }
|
||||
public int VoiceVol { get; set; }
|
||||
|
||||
public Task InitAsync(string mixerAddr = "AudioMixer", string soundPrefabAddr = "sound",
|
||||
string bgmGroupId = "BGM", string fishingGroupId = "Fishing", string uiGroupId = "UI", string voiceGroupId = "Voice");
|
||||
public void Release();
|
||||
public Sound GetNewBgmSound(AudioClip clip, bool loop = true, int priority = 0, float time = 0);
|
||||
public Sound GetNewFishingSound(AudioClip clip, bool loop = false, int priority = 128, float time = 0);
|
||||
public Sound GetNewUISound(AudioClip clip, bool loop = false, int priority = 128, float time = 0);
|
||||
public Sound GetNewVoiceSound(AudioClip clip);
|
||||
public void ReturnSound(Sound sound);
|
||||
public void FadeIn(Sound sound, float duration);
|
||||
public void FadeOut(Sound sound, float duration);
|
||||
}
|
||||
|
||||
public struct LowpassEffectEvt
|
||||
{
|
||||
public bool active;
|
||||
public float transTime;
|
||||
}
|
||||
|
||||
public class SoundService : ISoundService
|
||||
{
|
||||
[Inject]
|
||||
public IObjectPoolService poolService { set; private get; }
|
||||
|
||||
private AudioMixer mixer;
|
||||
private AudioMixerGroup bgmGroup;
|
||||
private AudioMixerGroup fishingGroup;
|
||||
private AudioMixerGroup uiGroup;
|
||||
private AudioMixerGroup voiceGroup;
|
||||
|
||||
private AsyncOperationHandle<AudioMixer> mixerHandle;
|
||||
private AsyncOperationHandle<GameObject> soundPrefabHandle;
|
||||
|
||||
private Dictionary<Sound, CancellationTokenSource> SoundFadeTaskDic;
|
||||
private float bgmVol = 0;
|
||||
private float fishingVol = 0;
|
||||
private const float Min_Vol = -80.0f;
|
||||
private const float Max_Vol = 20.0f;
|
||||
private const string Master_Vol_Param_Name = "masterVol";
|
||||
private const string Bgm_Vol_Param_Name = "bgmVol";
|
||||
private const string Fishing_Vol_Param_Name = "fishingVol";
|
||||
private const string UI_Vol_Param_Name = "uiVol";
|
||||
private const string Voice_Vol_Param_Name = "voiceVol";
|
||||
|
||||
|
||||
private const string Lowpass_Cutoff_Frq = "low_cut";
|
||||
private AudioMixerSnapshot normal;
|
||||
//private AudioMixerSnapshot lowpass;
|
||||
private IDisposable lowpassEvtDisposable;
|
||||
|
||||
private int _masterVol;
|
||||
public int MasterVol
|
||||
{
|
||||
get { return _masterVol; }
|
||||
set
|
||||
{
|
||||
_masterVol = value;
|
||||
mixer.SetFloat(Master_Vol_Param_Name, VolInt2Float(_masterVol));
|
||||
}
|
||||
}
|
||||
|
||||
private int _bgmVol;
|
||||
public int BGMVol
|
||||
{
|
||||
get { return _bgmVol; }
|
||||
set
|
||||
{
|
||||
_bgmVol = value;
|
||||
mixer.SetFloat(Bgm_Vol_Param_Name, VolInt2Float(_bgmVol) + bgmVol);
|
||||
}
|
||||
}
|
||||
|
||||
private int _sfxVol;
|
||||
public int SFXVol
|
||||
{
|
||||
get { return _sfxVol; }
|
||||
set
|
||||
{
|
||||
_sfxVol = value;
|
||||
mixer.SetFloat(Fishing_Vol_Param_Name, VolInt2Float(_sfxVol) + fishingVol);
|
||||
mixer.SetFloat(UI_Vol_Param_Name, VolInt2Float(_sfxVol));
|
||||
}
|
||||
}
|
||||
private int _voiceVol;
|
||||
public int VoiceVol
|
||||
{
|
||||
get { return _voiceVol; }
|
||||
set
|
||||
{
|
||||
_voiceVol = value;
|
||||
mixer.SetFloat(Voice_Vol_Param_Name, VolInt2Float(_voiceVol));
|
||||
}
|
||||
}
|
||||
private float VolInt2Float(int value)
|
||||
{
|
||||
var vol = Mathf.Clamp(value, 0f, 100f) / 100.0f;
|
||||
vol = Min_Vol + (Max_Vol - Min_Vol) * vol;
|
||||
return vol;
|
||||
}
|
||||
|
||||
private AudioMixerGroup FindMixerGroup(string groupId)
|
||||
{
|
||||
var groups = mixer.FindMatchingGroups(groupId);
|
||||
if (groups != null && groups.Length > 0)
|
||||
return groups[0];
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Audio mixer group {groupId} is not found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitAsync(string mixerAddr = "AudioMixer", string soundPrefabAddr = "sound",
|
||||
string bgmGroupId = "BGM", string fishingGroupId = "Fishing", string uiGroupId = "UI", string voiceGroupId = "Voice")
|
||||
{
|
||||
SoundFadeTaskDic = new Dictionary<Sound, CancellationTokenSource>();
|
||||
|
||||
mixerHandle = Addressables.LoadAssetAsync<AudioMixer>(mixerAddr);
|
||||
mixer = await mixerHandle.Task;
|
||||
Assert.IsNotNull(mixer);
|
||||
mixer.GetFloat(Bgm_Vol_Param_Name, out bgmVol);
|
||||
mixer.GetFloat(Fishing_Vol_Param_Name, out fishingVol);
|
||||
|
||||
bgmGroup = FindMixerGroup(bgmGroupId);
|
||||
fishingGroup = FindMixerGroup(fishingGroupId);
|
||||
uiGroup = FindMixerGroup(uiGroupId);
|
||||
voiceGroup = FindMixerGroup(voiceGroupId);
|
||||
normal = mixer.FindSnapshot("Snapshot");// ("normal");
|
||||
//lowpass = mixer.FindSnapshot("lowpass");
|
||||
Assert.IsNotNull(bgmGroup);
|
||||
Assert.IsNotNull(fishingGroup);
|
||||
Assert.IsNotNull(uiGroup);
|
||||
|
||||
soundPrefabHandle = Addressables.LoadAssetAsync<GameObject>(soundPrefabAddr);
|
||||
var soundPrefab = await soundPrefabHandle.Task;
|
||||
Assert.IsNotNull(soundPrefab);
|
||||
var sound = soundPrefab.GetComponent<Sound>();
|
||||
Assert.IsNotNull(sound);
|
||||
|
||||
lowpassEvtDisposable = GContext.OnEvent<LowpassEffectEvt>().Subscribe(OnLowpassEffectEvt);
|
||||
|
||||
poolService.CreatePool<Sound>(sound, 10, 50);
|
||||
}
|
||||
|
||||
private void OnLowpassEffectEvt(LowpassEffectEvt evt)
|
||||
{
|
||||
//if (evt.active)
|
||||
//{
|
||||
// lowpass.TransitionTo(evt.transTime);
|
||||
// return;
|
||||
//}
|
||||
normal.TransitionTo(evt.transTime);
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
foreach (var source in SoundFadeTaskDic.Values)
|
||||
{
|
||||
source.Cancel();
|
||||
}
|
||||
SoundFadeTaskDic.Clear();
|
||||
SoundFadeTaskDic = null;
|
||||
|
||||
poolService.DestroyPool<Sound>();
|
||||
Addressables.Release(mixerHandle);
|
||||
Addressables.Release(soundPrefabHandle);
|
||||
|
||||
lowpassEvtDisposable.Dispose();
|
||||
lowpassEvtDisposable = null;
|
||||
}
|
||||
|
||||
public void FadeIn(Sound sound, float duration)
|
||||
{
|
||||
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
||||
{
|
||||
s.Cancel();
|
||||
SoundFadeTaskDic[sound].Dispose();
|
||||
SoundFadeTaskDic.Remove(sound);
|
||||
}
|
||||
var source = new CancellationTokenSource();
|
||||
var token = source.Token;
|
||||
SoundFadeTaskDic.Add(sound, source);
|
||||
DoFade(0f, 1f, sound, duration, token);
|
||||
}
|
||||
|
||||
public void FadeOut(Sound sound, float duration)
|
||||
{
|
||||
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
||||
{
|
||||
s.Cancel();
|
||||
SoundFadeTaskDic[sound].Dispose();
|
||||
SoundFadeTaskDic.Remove(sound);
|
||||
}
|
||||
var source = new CancellationTokenSource();
|
||||
var token = source.Token;
|
||||
SoundFadeTaskDic.Add(sound, source);
|
||||
DoFade(1f, 0f, sound, duration, token);
|
||||
}
|
||||
|
||||
public Sound GetNewBgmSound(AudioClip clip, bool loop = true, int priority = 0, float time = 0)
|
||||
{
|
||||
var sound = poolService.SpawnObject<Sound>();
|
||||
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
||||
var audioSource = sound.audioSource;
|
||||
audioSource.clip = clip;
|
||||
audioSource.loop = loop;
|
||||
audioSource.priority = priority;
|
||||
audioSource.time = time;
|
||||
audioSource.outputAudioMixerGroup = bgmGroup;
|
||||
audioSource.Pause();
|
||||
return sound;
|
||||
}
|
||||
|
||||
public Sound GetNewFishingSound(AudioClip clip, bool loop = false, int priority = 128, float time = 0)
|
||||
{
|
||||
var sound = poolService.SpawnObject<Sound>();
|
||||
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
||||
var audioSource = sound.audioSource;
|
||||
audioSource.clip = clip;
|
||||
audioSource.loop = loop;
|
||||
audioSource.priority = priority;
|
||||
audioSource.time = time;
|
||||
audioSource.outputAudioMixerGroup = fishingGroup;
|
||||
return sound;
|
||||
}
|
||||
public Sound GetNewUISound(AudioClip clip, bool loop = false, int priority = 128, float time = 0)
|
||||
{
|
||||
var sound = poolService.SpawnObject<Sound>();
|
||||
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
||||
var audioSource = sound.audioSource;
|
||||
audioSource.clip = clip;
|
||||
audioSource.loop = loop;
|
||||
audioSource.priority = priority;
|
||||
audioSource.time = time;
|
||||
audioSource.outputAudioMixerGroup = uiGroup;
|
||||
return sound;
|
||||
}
|
||||
public Sound GetNewVoiceSound(AudioClip clip)
|
||||
{
|
||||
var sound = poolService.SpawnObject<Sound>();
|
||||
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
||||
var audioSource = sound.audioSource;
|
||||
audioSource.clip = clip;
|
||||
audioSource.loop = false;
|
||||
audioSource.priority = 128;
|
||||
audioSource.time = 0;
|
||||
audioSource.outputAudioMixerGroup = voiceGroup;
|
||||
return sound;
|
||||
}
|
||||
public void ReturnSound(Sound sound)
|
||||
{
|
||||
if (SoundFadeTaskDic == null || sound == null)
|
||||
return;
|
||||
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
||||
{
|
||||
s.Cancel();
|
||||
SoundFadeTaskDic[sound].Dispose();
|
||||
SoundFadeTaskDic.Remove(sound);
|
||||
}
|
||||
if (sound.enabled)
|
||||
{
|
||||
poolService.DespawnObject(sound);
|
||||
}
|
||||
}
|
||||
|
||||
private async void DoFade(float startVol, float endVol, Sound sound, float duration, CancellationToken ct)
|
||||
{
|
||||
var elapsedTime = 0f;
|
||||
sound.audioSource.volume = startVol;
|
||||
|
||||
try
|
||||
{
|
||||
while (elapsedTime < duration)
|
||||
{
|
||||
if (ct.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sound.audioSource.volume = Mathf.Lerp(startVol, endVol, elapsedTime / duration);
|
||||
elapsedTime += Time.deltaTime;
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
Assert.IsNotNull(sound);
|
||||
sound.audioSource.volume = endVol;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!ct.IsCancellationRequested && SoundFadeTaskDic != null)
|
||||
{
|
||||
SoundFadeTaskDic[sound].Dispose();
|
||||
SoundFadeTaskDic.Remove(sound);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user