Files
MinFt/Client/Assets/Scripts/Core/SoundMgr.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

817 lines
30 KiB
C#

using UnityEngine;
using asap.core;
using UnityEngine.AddressableAssets;
using System.Collections.Generic;
using UniRx;
using GameCore;
using cfg;
using game;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Linq;
using System.Threading.Tasks;
namespace Game
{
public struct ChangeRodDataEvent
{
public ChangeRodDataEvent(int rodId)
{
RodId = rodId;
}
public int RodId;
}
public interface IEventData
{
public SoundType audioType { set; get; }
public string audioNameStr { set; get; }
public float time { set; get; }
}
public class EventFishingSound : IEventData
{
public EventFishingSound(SoundType audioName, float time = 0, bool loop = false)
{
this.audioType = audioName;
this.audioNameStr = audioName.ToString();
this.time = time;
this.loop = loop;
}
public EventFishingSound(string audioName, float time = 0)
{
this.audioType = SoundType.Fishing;
this.audioNameStr = audioName;
this.time = time;
}
public Sound Sound { set; get; }
public SoundType audioType { set; get; }
public string audioNameStr { set; get; }
public float time { set; get; }
public bool loop { set; get; }
public bool SkipPendingPlayback { set; get; }
}
public class EventUISound : IEventData
{
public EventUISound(SoundType audioName, float time = 0)
{
this.audioType = audioName;
this.audioNameStr = audioName.ToString();
this.time = time;
}
public EventUISound(string audioName, float time = 0)
{
this.audioType = SoundType.UI;
this.audioNameStr = audioName;
this.time = time;
}
public Sound Sound { set; get; }
public SoundType audioType { set; get; }
public string audioNameStr { set; get; }
public float time { set; get; }
}
public class EventRewardSound : IEventData
{
public EventRewardSound(SoundType audioName, float time = 0)
{
this.audioType = audioName;
this.audioNameStr = audioName.ToString();
this.time = time;
}
public EventRewardSound(string audioName, float time = 0)
{
this.audioType = SoundType.UI;
this.audioNameStr = audioName;
this.time = time;
}
public Sound Sound { set; get; }
public SoundType audioType { set; get; }
public string audioNameStr { set; get; }
public float time { set; get; }
}
public class EventBGMSound : IEventData
{
public EventBGMSound(string audioName, float time = 0)
{
this.audioType = SoundType.BGM;
this.audioNameStr = audioName;
this.time = time;
}
public SoundType audioType { set; get; }
public string audioNameStr { set; get; }
public float time { set; get; }
}
public class FadeOutEvent
{
public FadeOutEvent(Sound sound, float timer = 0.5f)
{
this.sound = sound;
this.timer = timer;
}
public Sound sound { set; get; }
public float timer { set; get; }
}
public struct SoundMuteEvent
{
public SoundMuteEvent(int muteType)
{
this.muteType = muteType;
}
public int muteType;
}
public class AssetReferenceAudioClip
{
public AssetReferenceAudioClip(AssetReferenceT<AudioClip> assetReference, bool isOutDisable = false, SoundMainType mainType = SoundMainType.UI, float time = 0)
{
this.assetReference = assetReference;
this.time = time;
this.mainType = mainType;
this.isOutDisable = isOutDisable;
}
public AssetReferenceT<AudioClip> assetReference;
public Sound Sound { set; get; }
public float time { set; get; }
public SoundMainType mainType { set; get; }
public bool isOutDisable = false;
}
public class AssetReferenceAudioVoiceClip
{
public AssetReferenceAudioVoiceClip(AssetReferenceT<AudioClip> assetReference)
{
this.assetReference = assetReference;
}
public AssetReferenceT<AudioClip> assetReference;
public Sound Sound { set; get; }
}
public class OnSoundStateEvent
{
public OnSoundStateEvent(int type)
{
this.type = type;
}
public int type;
}
public class SoundMgr
{
[Inject]
public ISoundService soundService { set; get; }
public Tables _tables { set; get; }
string[] residentFish =
{ SoundType.audio_fishing_waiting.ToString(),
SoundType.audio_fishing_waiting.ToString(),
SoundType.audio_fishing_waiting_fishgathering.ToString(),
"audio_fishing_drawing_hpevent_01", "audio_fishing_drawing_hpevent_02","audio_fishing_drawing_hpevent_03","audio_fishing_drawing_hpevent_04","audio_fishing_drawing_hpevent_05",
SoundType.audio_fishing_welldone.ToString(),
SoundType.audio_fishing_switchrod.ToString(),
SoundType.audio_ui_targetcollect_collecting.ToString(),
SoundType.audio_ui_targetcollect_fly.ToString(),
"audio_fishing_pulling_fishflapping_01","audio_fishing_pulling_fishflapping_02","audio_fishing_pulling_fishflapping_03",
SoundType.audio_ui_fishingmap_btn_levelup.ToString(),
SoundType.audio_ui_fishingmap_fishpointfly.ToString(),
SoundType.audio_fishing_dash.ToString(),
SoundType.audio_fishing_fail_forcetoobig.ToString(),
SoundType.audio_fishing_fail_forcetoosmall.ToString(),
"audio_fishing_piercing01","audio_fishing_piercing02","audio_fishing_piercing03",
};
Dictionary<string, AudioClip> residentClip;
Sound BGM_Sound;
AudioClip BGM_Clip;
RodSkinData rodData;
OnSoundStateEvent onSoundState = new OnSoundStateEvent(0);
string BGMName;
Dictionary<string, Sound> rewardSoundDic = new Dictionary<string, Sound>();
readonly HashSet<Sound> _activeFishingLoopSounds = new HashSet<Sound>();
/// <summary>Reward 类音效全局节流:短间隔内只允许触发一次(与具体 clip 无关)。</summary>
const float RewardSoundThrottleSeconds = 0.2f;
float _rewardSoundLastPlayRealtime = -1000f;
bool TryConsumeRewardSoundThrottle()
{
float now = Time.realtimeSinceStartup;
if (now - _rewardSoundLastPlayRealtime < RewardSoundThrottleSeconds)
{
return false;
}
_rewardSoundLastPlayRealtime = now;
return true;
}
protected CompositeDisposable disposables;
public async Task Init(System.Action<float> progress)
{
//playerData = GContext.container.Resolve<PlayerData>();
_tables = GContext.container.Resolve<cfg.Tables>();
//var service = (SoundService)soundService;
await soundService.InitAsync();
var opMap = new Dictionary<string, AsyncOperationHandle<AudioClip>>();
foreach (var addr in residentFish)
{
opMap[addr] = Addressables.LoadAssetAsync<AudioClip>(addr);
}
var tasks = opMap.Values.Select(_ => _.Task);
var total = (float)tasks.Count();
while (true)
{
var completed = tasks.Count(_ => _.IsCompleted);
if (completed == total)
{
progress.Invoke(1f);
break;
}
else
{
progress.Invoke(completed / total);
}
await Awaiters.NextFrame;
}
residentClip = opMap.ToDictionary(_ => _.Key, _ => _.Value.Result);
disposables = new CompositeDisposable();
GContext.OnEvent<EventUISound>().Subscribe(PlaySound).AddTo(disposables);
GContext.OnEvent<EventRewardSound>().Subscribe(PlayRewardSound).AddTo(disposables);
GContext.OnEvent<EventFishingSound>().Subscribe(PlayFishingSound).AddTo(disposables);
GContext.OnEvent<EventBGMSound>().Subscribe(PlayMusic).AddTo(disposables);
GContext.OnEvent<FadeOutEvent>().Subscribe(FadeOutEvent).AddTo(disposables);
GContext.OnEvent<AssetReferenceAudioClip>().Subscribe(PlaySoundByReference).AddTo(disposables);
GContext.OnEvent<AssetReferenceAudioVoiceClip>().Subscribe(PlayVoiceSoundByReference).AddTo(disposables);
GContext.OnEvent<ChangeRodDataEvent>().Subscribe(OnChangeRodData).AddTo(disposables);
GContext.OnEvent<SoundMuteEvent>().Subscribe(OnSoundMute).AddTo(disposables);
GContext.OnEvent<OnSoundStateEvent>().Subscribe(OnSoundStateEvent).AddTo(disposables);
soundService.BGMVol = GContext.container.Resolve<ISettingService>().Music ? 80 : 0;
soundService.SFXVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
soundService.VoiceVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
}
void OnSoundStateEvent(OnSoundStateEvent onSoundStateEvent)
{
onSoundState = onSoundStateEvent;
SetSoundVolume(onSoundStateEvent.type);
}
void OnSoundMute(SoundMuteEvent soundMuteEvent)
{
if (soundMuteEvent.muteType == 0)
{
soundService.BGMVol = GContext.container.Resolve<ISettingService>().Music ? 80 : 0;
}
else
{
soundService.VoiceVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
soundService.SFXVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
}
}
public async void OnChangeRodData(ChangeRodDataEvent changeRodDataEvent)
{
AudioClip audioClip;
if (rodData != null)
{
if (residentClip.TryGetValue(rodData.ThrowingAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.ThrowingAudio);
}
if (residentClip.TryGetValue(rodData.ReelingAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.ReelingAudio);
}
if (residentClip.TryGetValue(rodData.LineAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.LineAudio);
}
if (residentClip.TryGetValue(rodData.ComboOutAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.ComboOutAudio);
}
if (residentClip.TryGetValue(rodData.ComboLoopAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.ComboLoopAudio);
}
if (residentClip.TryGetValue(rodData.ComboIntoAudio, out audioClip))
{
Addressables.Release(audioClip);
residentClip.Remove(rodData.ComboIntoAudio);
}
}
int skindID = GContext.container.Resolve<PlayerFishData>().GetRodSkin(changeRodDataEvent.RodId);
rodData = _tables.TbRodSkinData.GetOrDefault(skindID);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.ThrowingAudio).Task;
residentClip.Add(rodData.ThrowingAudio, audioClip);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.ReelingAudio).Task;
residentClip.Add(rodData.ReelingAudio, audioClip);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.LineAudio).Task;
residentClip.Add(rodData.LineAudio, audioClip);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.ComboOutAudio).Task;
residentClip.Add(rodData.ComboOutAudio, audioClip);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.ComboLoopAudio).Task;
residentClip.Add(rodData.ComboLoopAudio, audioClip);
audioClip = await Addressables.LoadAssetAsync<AudioClip>(rodData.ComboIntoAudio).Task;
residentClip.Add(rodData.ComboIntoAudio, audioClip);
}
public async void PlaySoundByReference(AssetReferenceAudioClip eventSound)
{
string audioName = eventSound.assetReference.AssetGUID;
if (!residentClip.TryGetValue(audioName, out var audioClip) || audioClip == null)
{
if (audioClip == null)
{
residentClip.Remove(audioName);
}
var audioClipL = await Addressables.LoadAssetAsync<AudioClip>(eventSound.assetReference).Task;//.LoadAssetAsync<AudioClip>().Task;
if (disposables == null)
{
return;
}
if (residentClip.TryGetValue(audioName, out audioClip))
{
Addressables.Release(audioClipL);
}
else
{
residentClip.Add(audioName, audioClipL);
audioClip = audioClipL;
}
}
if (audioClip == null)
{
soundService.ReturnSound(eventSound.Sound);
eventSound.Sound = null;
return;
}
SoundMainType soundMainType = eventSound.mainType;
if (soundMainType == SoundMainType.Reward && !TryConsumeRewardSoundThrottle())
{
return;
}
Sound sound;
switch (soundMainType)
{
case SoundMainType.None:
sound = null;
break;
case SoundMainType.BGM:
await PlayBGM(audioClip, eventSound.time);
residentClip.Remove(audioName);
if (disposables == null)
{
return;
}
return;
case SoundMainType.Fishing:
sound = soundService.GetNewFishingSound(audioClip, time: eventSound.time);
sound.soundMainType = SoundMainType.Fishing;
break;
case SoundMainType.Voice:
SetSoundVolume(2);
sound = soundService.GetNewVoiceSound(audioClip);
sound.soundMainType = SoundMainType.Voice;
break;
case SoundMainType.UILoop:
sound = soundService.GetNewUISound(audioClip, loop: true, time: eventSound.time);
sound.soundMainType = SoundMainType.UI;
break;
//case SoundMainType.UI:
default:
sound = soundService.GetNewUISound(audioClip, time: eventSound.time);
sound.soundMainType = soundMainType;
break;
}
if (sound != null)
{
if (soundMainType == SoundMainType.Reward)
{
if (rewardSoundDic.TryGetValue(audioName, out Sound reward))
{
if (reward.soundMainType == SoundMainType.Reward)
{
soundService.ReturnSound(reward);
}
}
rewardSoundDic[audioName] = sound;
}
sound.audioSource.Play();
eventSound.Sound = sound;
await Awaiters.Seconds(audioClip.length);
if (eventSound.Sound.soundMainType == SoundMainType.Voice)
{
SetSoundVolume(onSoundState.type);
}
if (soundMainType == eventSound.Sound.soundMainType && !eventSound.isOutDisable)
{
soundService.ReturnSound(sound);
eventSound.Sound = null;
}
}
}
async void PlayVoiceSoundByReference(AssetReferenceAudioVoiceClip eventSound)
{
var audioClip = await Addressables.LoadAssetAsync<AudioClip>(eventSound.assetReference).Task; // eventSound.assetReference.LoadAssetAsync<AudioClip>().Task;
if (audioClip == null)
{
eventSound.Sound = null;
return;
}
SetSoundVolume(2);
var sound = soundService.GetNewVoiceSound(audioClip);
sound.soundMainType = SoundMainType.Voice;
sound.audioSource.Play();
eventSound.Sound = sound;
await Awaiters.Seconds(audioClip.length);
if (eventSound.Sound.soundMainType == SoundMainType.Voice)
{
SetSoundVolume(onSoundState.type);
soundService.ReturnSound(sound);
}
Addressables.Release(audioClip);
eventSound.Sound = null;
}
/// <summary>
/// 0默认 type==1 钓鱼 type==2 人声
/// </summary>
/// <param name="type"></param>
void SetSoundVolume(int type)
{
if (GContext.container.Resolve<ISettingService>().Music)
{
soundService.BGMVol = type == 0 ? 80 : 72;
}
if (GContext.container.Resolve<ISettingService>().Sound)
{
soundService.SFXVol = type == 2 ? 70 : 80;
}
}
public async void PlaySound(EventUISound eventSound)
{
string audioName = GetAudioName(eventSound);
if (!residentClip.TryGetValue(audioName, out var audioClip))
{
var audioClipL = await Addressables.LoadAssetAsync<AudioClip>(audioName).Task;
if (residentClip.TryGetValue(audioName, out audioClip))
{
Addressables.Release(audioClipL);
}
else
{
residentClip.Add(audioName, audioClipL);
audioClip = audioClipL;
}
}
if (audioClip == null)
{
eventSound.Sound = null;
return;
}
var sound = soundService.GetNewUISound(audioClip, time: eventSound.time);
sound.soundMainType = SoundMainType.UI;
sound.audioSource.Play();
eventSound.Sound = sound;
await Awaiters.Seconds(audioClip.length);
if (SoundMainType.UI == eventSound.Sound.soundMainType)
{
soundService.ReturnSound(sound);
}
eventSound.Sound = null;
}
public async void PlayRewardSound(EventRewardSound eventSound)
{
string audioName = GetAudioName(eventSound);
if (!residentClip.TryGetValue(audioName, out var audioClip))
{
var audioClipL = await Addressables.LoadAssetAsync<AudioClip>(audioName).Task;
if (residentClip.TryGetValue(audioName, out audioClip))
{
Addressables.Release(audioClipL);
}
else
{
residentClip.Add(audioName, audioClipL);
audioClip = audioClipL;
}
}
if (audioClip == null)
{
eventSound.Sound = null;
return;
}
if (!TryConsumeRewardSoundThrottle())
{
eventSound.Sound = null;
return;
}
SoundMainType soundMainType = SoundMainType.Reward;
Sound sound = soundService.GetNewUISound(audioClip, time: eventSound.time);
sound.soundMainType = soundMainType;
if (rewardSoundDic.TryGetValue(audioName, out Sound reward))
{
if (reward.soundMainType == SoundMainType.Reward)
{
soundService.ReturnSound(reward);
}
}
rewardSoundDic[audioName] = sound;
sound.audioSource.Play();
eventSound.Sound = sound;
await Awaiters.Seconds(audioClip.length);
if (SoundMainType.Reward == eventSound.Sound.soundMainType)
{
soundService.ReturnSound(sound);
}
eventSound.Sound = null;
}
public async void PlayFishingSound(EventFishingSound eventSound)
{
string audioName = GetAudioName(eventSound);
if (!residentClip.TryGetValue(audioName, out var audioClip))
{
var audioClipL = await Addressables.LoadAssetAsync<AudioClip>(audioName).Task;
if (residentClip.TryGetValue(audioName, out audioClip))
{
Addressables.Release(audioClipL);
}
else
{
residentClip.Add(audioName, audioClipL);
audioClip = audioClipL;
}
}
if (audioClip == null)
{
eventSound.Sound = null;
return;
}
if (eventSound.SkipPendingPlayback)
{
eventSound.Sound = null;
return;
}
bool isLoop = eventSound.loop;
//if (eventSound.audioType == SoundType.LineAudioReeling || eventSound.audioType == SoundType.ReelingAudioReeling)
//{
// isLoop = true;
//}
var sound = soundService.GetNewFishingSound(audioClip, loop: isLoop, time: eventSound.time);
sound.soundMainType = SoundMainType.Fishing;
sound.audioSource.Play();
eventSound.Sound = sound;
if (isLoop)
{
_activeFishingLoopSounds.Add(sound);
}
if (!isLoop)
{
await Awaiters.Seconds(audioClip.length);
if (eventSound.Sound != null && SoundMainType.Fishing == eventSound.Sound.soundMainType)
{
soundService.ReturnSound(sound);
}
eventSound.Sound = null;
}
}
public void StopActiveFishingLoopSounds(float fadeSeconds = 0.35f)
{
var copy = _activeFishingLoopSounds.ToList();
foreach (var s in copy)
{
if (s != null)
{
FadeOutAsync(s, fadeSeconds);
}
}
}
public async Task PlayFishingSound(string audioName)
{
if (!residentClip.TryGetValue(audioName, out var audioClip))
{
var audioClipL = await Addressables.LoadAssetAsync<AudioClip>(audioName).Task;
if (residentClip.TryGetValue(audioName, out audioClip))
{
Addressables.Release(audioClipL);
}
else
{
residentClip.Add(audioName, audioClipL);
audioClip = audioClipL;
}
}
if (audioClip == null)
{
return;
}
var sound = soundService.GetNewFishingSound(audioClip);
sound.soundMainType = SoundMainType.Fishing;
sound.audioSource.Play();
await Awaiters.Seconds(audioClip.length);
soundService.ReturnSound(sound);
}
public async void PlayMusic(EventBGMSound eventSound)
{
string audioName = GetAudioName(eventSound);
if (BGMName == audioName)
{
return;
}
var audioClip = await Addressables.LoadAssetAsync<AudioClip>(audioName).Task;
if (BGMName == audioName)
{
Addressables.Release(audioClip);
return;
}
await PlayBGM(audioClip, eventSound.time);
}
async Task PlayBGM(AudioClip audioClip, float time = 0)
{
if (audioClip == null)
{
return;
}
BGMName = audioClip.name;
if (BGM_Clip != null)
{
AudioClip audioClip1 = BGM_Clip;
BGM_Clip = null;
Sound bgm_Sound = BGM_Sound;
BGM_Sound = null;
soundService.FadeOut(bgm_Sound, 0.5f);
await Task.Delay(500);
Addressables.Release(audioClip1);
soundService.ReturnSound(bgm_Sound);
}
if (BGMName != audioClip.name)
{
return;
}
BGM_Sound = soundService.GetNewBgmSound(audioClip, time: time);
BGM_Sound.soundMainType = SoundMainType.BGM;
BGM_Clip = audioClip;
BGM_Sound.audioSource.Play();
soundService.FadeIn(BGM_Sound, 0.5f);
}
public void SetBGM(AudioClip audioClip)
{
if (audioClip == BGM_Clip)
return;
if (BGM_Sound == null)
{
BGM_Sound = soundService.GetNewBgmSound(audioClip);
}
BGM_Sound.audioSource.clip = audioClip;
BGM_Sound.soundMainType = SoundMainType.BGM;
BGM_Clip = audioClip;
BGM_Sound.audioSource.Play();
}
void FadeOutEvent(FadeOutEvent fadeOutEvent)
{
FadeOutAsync(fadeOutEvent.sound, fadeOutEvent.timer);
fadeOutEvent.sound = null;
}
async void FadeOutAsync(Sound sound, float timer = 0.5f)
{
if (sound == null)
{
return;
}
try
{
_activeFishingLoopSounds.Remove(sound);
if (sound.soundMainType == SoundMainType.Voice)
{
SetSoundVolume(onSoundState.type);
}
if (sound.soundMainType == SoundMainType.BGM)
{
return;
}
soundService.FadeOut(sound, timer);
await Task.Delay((int)(timer * 1000));
if (sound.soundMainType != SoundMainType.None)
{
soundService.ReturnSound(sound);
}
}
catch (System.Exception e)
{
Debug.LogError(e);
soundService.ReturnSound(sound);
}
}
string GetAudioName(IEventData eventData)
{
PlayerData playerData = GContext.container.Resolve<PlayerData>();
PlayerFishData playerFishData = GContext.container.Resolve<PlayerFishData>();
int skindID = playerFishData.GetRodSkin(playerData.equipRodID);
RodSkinData rodSkinData = _tables.TbRodSkinData.GetOrDefault(skindID);
switch (eventData.audioType)
{
case SoundType.ThrowingAudio:
return rodSkinData.ThrowingAudio;
case SoundType.ReelingAudio:
case SoundType.ReelingAudioReeling:
return rodSkinData.ReelingAudio;
case SoundType.LineAudioReeling:
return rodSkinData.LineAudio;
case SoundType.ComboOutAudio:
return rodSkinData.ComboOutAudio;
case SoundType.ComboLoopAudio:
return rodSkinData.ComboLoopAudio;
case SoundType.ComboIntoAudio:
return rodSkinData.ComboIntoAudio;
case SoundType.HPEvent:
return "audio_fishing_drawing_hpevent_0" + Random.Range(1, 6);
case SoundType.audio_fishing_piercing:
return "audio_fishing_piercing0" + Random.Range(1, 4);
case SoundType.audio_fishing_jumpout:
return "audio_fishing_jumpout_0" + Random.Range(1, 4);
case SoundType.audio_fishing_jumpinto:
return "audio_fishing_jumpinto_0" + Random.Range(1, 4);
case SoundType.BGM:
case SoundType.Fishing:
case SoundType.UI:
default:
return eventData.audioNameStr;
}
}
public void Release()
{
if (disposables != null)
{
disposables.Dispose();
disposables = null;
}
if (residentClip != null)
{
foreach (var item in residentClip)
{
if (item.Value != null)
{
Addressables.Release(item.Value);
}
}
residentClip.Clear();
}
if (rewardSoundDic != null)
{
rewardSoundDic.Clear();
}
if (soundService != null)
{
foreach (var s in _activeFishingLoopSounds.ToList())
{
if (s != null)
{
s.audioSource.Stop();
soundService.ReturnSound(s);
}
}
}
_activeFishingLoopSounds.Clear();
if (soundService != null)
{
soundService.Release();
}
if (BGM_Clip != null)
{
Addressables.Release(BGM_Clip);
BGM_Clip = null;
}
if (BGM_Sound != null && BGM_Sound.gameObject != null)
{
GameObject.Destroy(BGM_Sound.gameObject);
BGM_Sound = null;
}
BGMName = null;
}
}
}