--region *.lua --Date --此文件由[BabeLua]插件自动生成 local _IsLog = false local function __DebugLog(content) if _IsLog then Log(""..content.."") end end SoundManager = { } local eAudioType = { uiAudio = 1, bgAudio = 2, amAudio = 3, } AUDIO_RUN_TYPE = { -- 音效切换执行方式 SEQ = 1, -- 顺序 CONC = 2 -- 并发 } AUDIO_FADE_TYPE = { -- 音效淡入淡出方式 FADE_OUT_AND_IN = 1, -- 淡入淡出 FADE_OUT_NOT_IN = 2, -- 淡出不淡入 FADE_IN_NOT_OUT = 3, -- 淡入不淡出 DIRECT_CHANGE = 4 -- 直接变化 } SoundManager.soundChannelCount = 20 SoundManager.soundVolume = 1 SoundManager.backgroundSoundVolume = 1 SoundManager.cachePlayTime = 0.16 -- 相同音效的播放间隔 local _AudioPlayCD = 0.1 local _AudioPlayList = {} local _sfx_enabled = true local _bgm_enabled = true local _amb_enabled = true local _backgroundSound = {} local _backgroundRes local _backgroundResOld local _AmbientChannel = {} local _AmbientRes local _soundChannel = { } local AudioSource = UnityEngine.AudioSource local AudioConfig = {} local SoundDef = { "Music", --背景音 "Ambient", --环境音效 "common", --普通UI音效 "skill", --技能音效 --[[ "buff", --技能音效 4,5,6,7统一使用skill音轨进行处理 "monster", --技能音效 "yiyao", --技能音效 ]] "footsteps", -- 脚步声 "other", -- 其他ui音效 "special", -- 特殊ui音效 "Voice", -- 配音音效 } local _node function SoundManager.Clear() if _node ~= nil then SoundManager.ClearResource() GameObject.Destroy(_node) _node = nil end end function SoundManager.ClearResource() -- 资源回收 for i = 1, SoundManager.soundChannelCount do local audioUnit = _soundChannel[i] if audioUnit then audioUnit.audio:Stop() if audioUnit.audio.clip then if audioUnit.audioType == eAudioType.uiAudio then poolManager:UnLoadAsset(audioUnit.audio.clip.name,audioUnit.audio.clip, PoolManager.AssetType.MediaUI) audioUnit.audio.clip = nil end end end end if _backgroundSound then for i = 1, #_backgroundSound do local audioBg = _backgroundSound[i] if audioBg then audioBg.audio:Stop() if audioBg.audio.clip then poolManager:UnLoadAsset(audioBg.audio.clip.name,audioBg.audio.clip, PoolManager.AssetType.MediaUI) audioBg.audio.clip = nil end end end end if _AmbientChannel then for i = 1, #_AmbientChannel do local audioBg = _AmbientChannel[i] if audioBg then audioBg.audio:Stop() if audioBg.audio.clip then poolManager:UnLoadAsset(audioBg.audio.clip.name,audioBg.audio.clip, PoolManager.AssetType.MediaUI) audioBg.audio.clip = nil end end end end end function SoundManager.Initialize() SoundManager.Clear() _node = GameObject("Sound Listener") GameObject.DontDestroyOnLoad(_node) for k, v in ConfigPairs(ConfigManager.GetConfig(ConfigName.AudioConfig)) do AudioConfig[v.Name] = { mixType = SoundDef[v.Type], isLoop = v.Loop == 1 } end for i = 1, SoundManager.soundChannelCount do local chanel = _node:AddComponent(typeof(AudioSource)) chanel.minDistance = 480 chanel.enabled = true chanel.playOnAwake = false chanel.loop = false local audioUnit = {} audioUnit.audio = chanel audioUnit.audioType = eAudioType.uiAudio audioUnit.isLock = false table.insert(_soundChannel, audioUnit) end local _as = _node:AddComponent(typeof(AudioSource)) _as.minDistance = 480 _as.playOnAwake = false _as.loop = false local audioUnit = {} audioUnit.audio = _as audioUnit.audioType = eAudioType.bgAudio audioUnit.isLock = false table.insert(_backgroundSound, audioUnit) local _am = _node:AddComponent(typeof(AudioSource)) _am.minDistance = 480 _am.playOnAwake = false _am.loop = false local audioUnit = {} audioUnit.audio = _am audioUnit.audioType = eAudioType.amAudio audioUnit.isLock = false table.insert(_AmbientChannel, audioUnit) end -- 外部改变音量大小 function SoundManager.ChangeSettingVolume(settingType, value) if settingType == SETTING_TYPE.BGM_RATIO then for _, unit in ipairs(_backgroundSound) do unit.audio.volume = SoundManager.backgroundSoundVolume * value end elseif settingType == SETTING_TYPE.SOUND_RATIO then for _, unit in ipairs(_soundChannel) do unit.audio.volume = SoundManager.backgroundSoundVolume * value end for _, unit in ipairs(_AmbientChannel) do unit.audio.volume = SoundManager.backgroundSoundVolume * value end end end -- 根据音效类型获取音效配置 local function GetAudioConfigByType(audioType) if audioType == eAudioType.uiAudio then return {volumeType = SETTING_TYPE.SOUND_RATIO, defaultVolume = 1} elseif audioType == eAudioType.bgAudio then return {volumeType = SETTING_TYPE.BGM_RATIO, defaultVolume = 1} elseif audioType == eAudioType.amAudio then return {volumeType = SETTING_TYPE.SOUND_RATIO, defaultVolume = 1} end end --[[ clipName:音效资源名字 channel:固定音轨 nil:用空闲音轨播放 ]] local function setAudioMixer(clipName, audioUnit) local config = AudioConfig[clipName] if not config then audioUnit.audio.loop = false return end if config.mixType and audioUnit.mixType ~= config.mixType then Util.SetAudioMixer(config.mixType, audioUnit.audio) audioUnit.mixType = config.mixType end audioUnit.audio.loop = config.isLoop end -- 设置audioUnit local function _SetAudioUnit(audioUnit, resName, auildType, volume) __DebugLog("_SetAudioUnit -------->"..resName) -- 获取声音文件 local clipNew = poolManager:LoadAsset(resName, PoolManager.AssetType.MediaBg) if not clipNew then return nil end -- 卸载旧音效 if audioUnit.audio.clip then poolManager:UnLoadAsset(audioUnit.audio.clip.name,audioUnit.audio.clip, PoolManager.AssetType.MediaBg) __DebugLog("卸载旧音效 -------->"..audioUnit.audio.clip.name) audioUnit.audio.clip = nil end -- 获取类型配置 if not volume then local audioTypeConfig = GetAudioConfigByType(auildType) local ratio = SettingManager.GetSettingData(audioTypeConfig.volumeType) volume = audioTypeConfig.defaultVolume * ratio end -- 是否循环 local config = AudioConfig[resName] local isLoop = config and config.isLoop local pitch = 1 if auildType == eAudioType.uiAudio then if config and config.mixType == SoundDef[4] then if UIManager.IsOpen(UIName.BattlePanel) then local scale = BattleManager.GetTimeScale() pitch = math.floor(scale + 0.5) end end end -- 播放新音效 if not config or config.mixType == SoundDef[1] or config.mixType == SoundDef[2] or isLoop then audioUnit.audio.clip = clipNew audioUnit.audio.volume = volume audioUnit.audioType = auildType audioUnit.audio.loop = isLoop audioUnit.audio.pitch = pitch audioUnit.audio:Play() else audioUnit.audio:PlayOneShot(clipNew, volume) audioUnit.audio.pitch = pitch end setAudioMixer(resName, audioUnit) end local function _StopAudioUnit(audioUnit) -- 卸载旧音效 if audioUnit.audio.clip then poolManager:UnLoadAsset(audioUnit.audio.clip.name,audioUnit.audio.clip, PoolManager.AssetType.MediaBg) __DebugLog("卸载旧音效 -------->"..audioUnit.audio.clip.name) audioUnit.audio.clip = nil end audioUnit.audio:Stop() end local _FadeTime = 1 local function _FadeOutUnit(audioUnit, _FadeDone) if not audioUnit then if _FadeDone then _FadeDone() end end -- 声音淡出 DoTween.To( DG.Tweening.Core.DOGetter_float( function () return audioUnit.audio.volume end), DG.Tweening.Core.DOSetter_float( function (progress) audioUnit.audio.volume = progress end), 0, _FadeTime) :SetEase(Ease.Linear) :OnComplete( function () -- 淡出完成回调 _StopAudioUnit(audioUnit) if _FadeDone then _FadeDone() end end) end local function _FadeInUnit(audioUnit, auildType, _FadeDone) if not audioUnit then if _FadeDone then _FadeDone() end end -- 获取类型配置 local audioTypeConfig = GetAudioConfigByType(auildType) -- 声音淡入 DoTween.To( DG.Tweening.Core.DOGetter_float( function () return 0 end), DG.Tweening.Core.DOSetter_float(function (progress) local ratio = SettingManager.GetSettingData(audioTypeConfig.volumeType) audioUnit.audio.volume = progress * ratio end), audioTypeConfig.defaultVolume, _FadeTime) :SetEase(Ease.Linear) :OnComplete(function() -- 淡入完成回调 if _FadeDone then _FadeDone() end end) end -- 切换音效 local function _ChangeAudio(outUnit, inUnit, resName, audioType, fadeType, runType, _FadeOutDone, _FadeInDone) fadeType = fadeType or AUDIO_FADE_TYPE.DIRECT_CHANGE runType = runType or AUDIO_RUN_TYPE.SEQ if fadeType == AUDIO_FADE_TYPE.FADE_OUT_AND_IN then if runType == AUDIO_RUN_TYPE.SEQ then _FadeOutUnit(outUnit, function() -- 淡出完成回调 _SetAudioUnit(inUnit, resName, audioType, 0) if _FadeOutDone then _FadeOutDone() end _FadeInUnit(inUnit, audioType, _FadeInDone) end) elseif runType == AUDIO_RUN_TYPE.CONC then _FadeOutUnit(outUnit, _FadeOutDone) _SetAudioUnit(inUnit, resName, audioType, 0) _FadeInUnit(inUnit, audioType, _FadeInDone) end elseif fadeType == AUDIO_FADE_TYPE.FADE_OUT_NOT_IN then if runType == AUDIO_RUN_TYPE.SEQ then _FadeOutUnit(outUnit, function() -- 淡出完成回调 _SetAudioUnit(inUnit, resName, audioType) if _FadeOutDone then _FadeOutDone() end if _FadeInDone then _FadeInDone() end end) elseif runType == AUDIO_RUN_TYPE.CONC then _FadeOutUnit(outUnit, _FadeOutDone) _SetAudioUnit(inUnit, resName, audioType) if _FadeInDone then _FadeInDone() end end elseif fadeType == AUDIO_FADE_TYPE.FADE_IN_NOT_OUT then -- 顺序,同步相同 _StopAudioUnit(outUnit) _SetAudioUnit(inUnit, resName, audioType, 0) if _FadeOutDone then _FadeOutDone() end _FadeInUnit(inUnit, _FadeInDone) elseif fadeType == AUDIO_FADE_TYPE.DIRECT_CHANGE then _StopAudioUnit(outUnit) _SetAudioUnit(inUnit, resName, audioType) if _FadeOutDone then _FadeOutDone() end if _FadeInDone then _FadeInDone() end end end ---- ==============================播放音效=================================== function SoundManager.PlaySound(clipName, fadeType, runType, channel, outChannel) if not clipName then return end __DebugLog("*****") -- 判断是否符合音效时间限制 if _AudioPlayList[clipName] then local startTime = _AudioPlayList[clipName].startTime local nowTime = Time.realtimeSinceStartup if nowTime - startTime < _AudioPlayCD then __DebugLog("与同名音效播放时间间隔小于cd时间被舍弃,音效:"..clipName) return end end local function _AddStartTime() -- 记录音效播放时间点 _AudioPlayList[clipName] = { startTime = Time.realtimeSinceStartup } end --找一个空闲的音源播放 if not channel then for i = 1, SoundManager.soundChannelCount do local audioUnit = _soundChannel[i] if not audioUnit.audio.isPlaying then channel = i break end end end if not channel then Log("播放音效失败,超出了最大数量的限制,音效:"..clipName) return end if not outChannel then outChannel = channel end __DebugLog("播放音效-------->"..clipName.."channel ->"..channel.."outChannel ->"..outChannel) local inUnit = _soundChannel[channel] local outUnit = _soundChannel[outChannel] _ChangeAudio(outUnit, inUnit, clipName, eAudioType.uiAudio, fadeType, runType, _AddStartTime) return inUnit end -- 通过通道关闭音效 function SoundManager.StopSoundByChannel(channel) local audioUnit = _soundChannel[channel] _StopAudioUnit(audioUnit) end -- 关闭音效 function SoundManager.StopSound(audioUnit) _StopAudioUnit(audioUnit) end --- =================================背景音====================================== local _MusicTimer = nil function SoundManager.PlayMusic(resName, isFade, callback) if resName == nil then return end if resName == _backgroundRes then return end if not _backgroundSound then return end local audioUnit = _backgroundSound[1] if not audioUnit then return end _backgroundResOld = _backgroundRes _backgroundRes = resName local function _SetTimer() -- 关闭音乐计时器 if _MusicTimer then _MusicTimer:Stop() _MusicTimer = nil end if callback then -- 获取声音文件 local config = AudioConfig[resName] local isLoop = config and config.isLoop _MusicTimer = Timer.New(callback, audioUnit.audio.clip.length, isLoop and -1 or 1, true) _MusicTimer:Start() end end local fadeType = AUDIO_FADE_TYPE.DIRECT_CHANGE if isFade == nil or isFade then fadeType = AUDIO_FADE_TYPE.FADE_OUT_AND_IN end _ChangeAudio(audioUnit, audioUnit, resName, eAudioType.bgAudio, fadeType, AUDIO_RUN_TYPE.SEQ, _SetTimer) end --暂停当前背景音乐 function SoundManager.StopMusic() local audioUnit = _backgroundSound[1] if audioUnit then audioUnit.audio:Stop() end -- 关闭音乐计时器 if _MusicTimer then _MusicTimer:Stop() _MusicTimer = nil end _backgroundRes = nil end function SoundManager.PlayOldMusic() SoundManager.PlayMusic(_backgroundResOld) end ---=============================环境音效============================================ function SoundManager.PlayAmbient(resName) if not resName then return end -- 播放相同音效 if resName == _AmbientRes then return end -- 通道检测 if not _AmbientChannel or not _AmbientChannel[1] then return end local audioUnit = _AmbientChannel[1] if not audioUnit then return end _AmbientRes = resName _ChangeAudio(audioUnit, audioUnit, resName, eAudioType.amAudio, AUDIO_FADE_TYPE.FADE_OUT_AND_IN, AUDIO_RUN_TYPE.SEQ) end --暂停当前背景音乐 function SoundManager.PauseAmbient() local audioUnit = _AmbientChannel[1] if audioUnit then -- 声音淡出 DoTween.To( DG.Tweening.Core.DOGetter_float( function () return audioUnit.audio.volume end), DG.Tweening.Core.DOSetter_float( function (progress) audioUnit.audio.volume = progress end), 0, 1) :SetEase(Ease.Linear) :OnComplete(function () audioUnit.audio:Pause() end) end _AmbientRes = nil end --- ========================== 音效控制=========================== function SoundManager.GetSoundEnabled() return _sfx_enabled end function SoundManager.SetSoundEnabled(b) if _sfx_enabled == b then return end _sfx_enabled = b end function SoundManager.GetBgmEnabled() return _bgm_enabled end function SoundManager.SetBgmEnabled(b) if _bgm_enabled == b then return end _bgm_enabled = b end -- 设置音效播放速度 function SoundManager.SetAudioSpeed(speed) speed = speed or 1 -- for _, unit in ipairs(_backgroundSound) do -- unit.audio.pitch = speed -- end -- for _, unit in ipairs(_soundChannel) do -- unit.audio.pitch = speed -- end -- for _, unit in ipairs(_AmbientChannel) do -- unit.audio.pitch = speed -- end end function SoundManager.Dispose() SoundManager.Clear() end --endregion