插件介绍:

Master Audio的是一个整体解决方案,所有的丰富的游戏音频需求。内置的音乐闪避,手动和自动的声音触发真正的随机声音变化,音频汇集全3D声音功能。支持所有出口的手机游戏平台,具有一流的性能。

主音频在线帮助网站可在此处找到:

Table of Contents

完整的主音频 API 文档可在此处找到:

Master Audio - AAA Sound Solution!: Main Page

实现功能:

  1. 音效要能与场景物件绑定,要能单独配置音量,支持相关配置方式
  2. 检查多个音效同时出现时的声音混合是否正常
  3. 提供动态调整某一大类音效音量的接口
  4. 脚步声配置

代码实现

这里不细说实现中使用MasterAudio插件的API了(可以直接去翻一下插件文档)。

  1. 动态创建音频组,提供音频的播放、停止接口
  2. 提供调节一组音频的音量大小
  3. 音效与场景物件绑定工具
  4. 脚步声配置工具

AudioSystem:

using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using DarkTonic.MasterAudio;
using System.Linq;
using CheapUtil;struct PlayAudioArgs
{public MasterAudioGroup group;public string path;public bool isLoop;public string callBack;public Vector3 position;public float volume;public float speed;public float startTime;
}public class AudioSystem : MonoBehaviour
{struct MasterAudioGroupConfig{public AudioType audioType;public string name;public int audioLimit;public bool is2DSound;public MasterAudioGroupConfig(AudioType audioType, string name, int audioLimit, bool is2DSound = true){this.audioType = audioType;this.name = name;this.audioLimit = audioLimit;this.is2DSound = is2DSound;}}#region 属性private static AudioSystem instance = null;public static AudioSystem Instance => instance;private float unloadTime = 5f;private MasterAudio masterAudio;private static readonly string groupTemplate = "Audio/DefaultSingle";private static readonly string audioSourceTemplate = "Audio/TemplatesDistance10";private Dictionary<AudioType, MasterAudioGroup>_masterAudioGroupDic = new Dictionary<AudioType, MasterAudioGroup>();private MasterAudioGroupConfig[] _masterAudioGroupConfig = new[]{new MasterAudioGroupConfig(AudioType.BGM, "BGM_SoundGroup", 0),new MasterAudioGroupConfig(AudioType.SE_2D, "2D_SoundGroup", 9),new MasterAudioGroupConfig(AudioType.SE_3D, "3D_SoundGroup", 9, false),new MasterAudioGroupConfig(AudioType.Voice, "Voice_SoundGroup", 0),new MasterAudioGroupConfig(AudioType.Footstep, "Footstep_SoundGroup", 9),};// 淡出携程,仅支持BGM和Voice(同时唯一播放)private Coroutine audioFadeOutCorBGM = null;private static PlayAudioArgs waitingBGM = new PlayAudioArgs();private Coroutine audioFadeOutCorVoice = null;private static PlayAudioArgs waitingVoice = new PlayAudioArgs();// 正在播放的音效数据private static List<SoundGroupVariation> sgvList = new List<SoundGroupVariation>();#endregion#region 初始化相关//初始化使用到的MasterAudio音乐组件public void Awake(){GameObject Masterad = new GameObject("MasterAudio");if (Masterad != null){DontDestroyOnLoad(Masterad);} //加载时不销毁此GameObjectmasterAudio = Masterad.AddComponent<MasterAudio>();//设置MasterAudio的参数值masterAudio.useGroupTemplates = true;GameObject groupTemplateObj = GameAssetProxy.Load(GameAssetType.DataPrefab, groupTemplate, false) as GameObject;masterAudio.groupTemplates.Add(groupTemplateObj);masterAudio.soundGroupTemplate = groupTemplateObj.transform;GameObject audioSourceTemplateObj =GameAssetProxy.Load(GameAssetType.DataPrefab, audioSourceTemplate, false) as GameObject;masterAudio.audioSourceTemplates.Add(audioSourceTemplateObj);masterAudio.soundGroupVariationTemplate = audioSourceTemplateObj.transform;masterAudio.musicSpatialBlendType = MasterAudio.AllMusicSpatialBlendType.AllowDifferentPerController;masterAudio.mixerSpatialBlendType = MasterAudio.AllMixerSpatialBlendType.AllowDifferentPerGroup;masterAudio.newGroupSpatialType = MasterAudio.ItemSpatialBlendType.UseCurveFromAudioSource;}private void Start(){InitAudioGroups();instance = this;}private void InitAudioGroups(){for (int i = 0; i < _masterAudioGroupConfig.Length; i++){var cfg = _masterAudioGroupConfig[i];MasterAudioGroup group = CreateSoundGroup(cfg.audioType, cfg.name, cfg.audioLimit, cfg.is2DSound);if (_masterAudioGroupDic.ContainsKey(cfg.audioType)){Debug.LogError("配置了相同类型的Group,请检查配置");}else{_masterAudioGroupDic.Add(cfg.audioType, group);}}}private MasterAudioGroup CreateSoundGroup(AudioType audioType, string rootName, int variationNum, bool is2DSound){// string rootName = GetAudioGroupName(audioType);Transform trans =MasterAudio.CreateSoundGroup(rootName, MasterAudio.Instance.gameObject, variationNum, is2DSound);MasterAudioGroup audioGroup = trans.GetComponent<MasterAudioGroup>();if (audioGroup == null){audioGroup = trans.gameObject.AddComponent<MasterAudioGroup>();}audioGroup.groupMasterVolume = GetAudioGroupVolume(audioType);return audioGroup;}float deltaTime = 0f;public void LateUpdate(){deltaTime += Time.deltaTime;if (deltaTime >= unloadTime){deltaTime = 0f;TryUnloadUselessClips();}}#endregion#region 开放方法/// <summary>/// 播放音效/// </summary>/// <param name="audioType">音效组类型</param>/// <param name="path">音效路径</param>/// <param name="volume">音量[0, 1] (仅该音效的音量,不指音效组总音量)</param>/// <param name="isLoop">是否循环播放</param>/// <param name="callBack">播放完毕回调</param>/// <param name="speed">播放速度</param>/// <param name="isFadeOut">是否淡出</param>/// <param name="fadeOutTime">淡出时长</param>/// <param name="posX">3D音效的位置</param>/// <param name="posY">3D音效的位置</param>/// <param name="posZ">3D音效的位置</param>public void PlayAudio(AudioType audioType, string path, float volume = 1f, bool isLoop = false,bool isFadeOut = false, float fadeOutTime = 1f,string callBack = null, float speed = 1f, float startTime = 0, float posX = 0f, float posY = 0f,float posZ = 0f){MasterAudioGroup group = GetAudioGroup(audioType);if (!TryLoadAudio(group, path)) return;if (volume > 1f) volume = 1f;if (volume < 0f) volume = 0f;bool canPlay = true;Coroutine curCor = GetAudioFadeOutCor(audioType);if (curCor != null){canPlay = false;}else{if (isFadeOut && AllowFadeOut(audioType)){SetAudioFadeOutCor(audioType, StartCoroutine(FadeOutAndPlayNext(fadeOutTime, audioType)));canPlay = false;}}if (canPlay){RealPlayAudio(group, path, isLoop, callBack, new Vector3(posX, posY, posZ), volume, speed, startTime);}else{if (audioType == AudioType.BGM){waitingBGM.group = group;waitingBGM.path = path;waitingBGM.isLoop = isLoop;waitingBGM.callBack = callBack;waitingBGM.position = new Vector3(posX, posY, posZ);waitingBGM.volume = volume;waitingBGM.speed = speed;waitingBGM.startTime = startTime;}else if (audioType == AudioType.Voice){waitingVoice.group = group;waitingVoice.path = path;waitingVoice.isLoop = isLoop;waitingVoice.callBack = callBack;waitingVoice.position = new Vector3(posX, posY, posZ);waitingVoice.volume = volume;waitingVoice.speed = speed;waitingVoice.startTime = startTime;}}}public void PlaySound3DAtVector3(AudioType audioType, string path, Vector3 pos, float volume = 1f,bool isLoop = false,float pitch = 1,float delayTime = 0, string callBack = null, float startTime = 0){MasterAudioGroup group = GetAudioGroup(audioType);if (!TryLoadAudio(group, path)) return;if (volume > 1f) volume = 1f;if (volume < 0f) volume = 0f;PlaySoundResult result = MasterAudio.PlaySound3DAtVector3(group.name,path,pos, volume, pitch, delayTime);        SetPlaySoundResult(result,path,isLoop,callBack,startTime);}public void PlaySound3DAtTransform(AudioType audioType, string path, Transform trans, float volume = 1f,bool isLoop = false,float pitch = 1,float delayTime = 0, string callBack = null, float startTime = 0){MasterAudioGroup group = GetAudioGroup(audioType);if (!TryLoadAudio(group, path)) return;if (volume > 1f) volume = 1f;if (volume < 0f) volume = 0f;PlaySoundResult result = MasterAudio.PlaySound3DAtTransform(group.name,path, trans, volume, pitch, delayTime);        SetPlaySoundResult(result,path,isLoop,callBack,startTime);}public void PlaySound3DFollowTransform(AudioType audioType, string path, Transform trans, float volume = 1f,bool isLoop = false,float pitch = 1,float delayTime = 0, string callBack = null, float startTime = 0){MasterAudioGroup group = GetAudioGroup(audioType);if (!TryLoadAudio(group, path)) return;if (volume > 1f) volume = 1f;if (volume < 0f) volume = 0f;PlaySoundResult result = MasterAudio.PlaySound3DFollowTransform(group.name,path, trans, volume, pitch, delayTime);        SetPlaySoundResult(result,path,isLoop,callBack,startTime);}public void StopAudio(AudioType audioType, string path){MasterAudioGroup group = GetAudioGroup(audioType);// 无法真正停止播放 // foreach(SoundGroupVariation var in group.groupVariations)// {//     if (var.IsPlaying && var.resourceFileName == path)//     {//         MasterAudio.StopVariationInSoundGroup(group.GameObjectName, var.name);//     }// }for (int i = 0; i < sgvList.Count; i++){var sgv = sgvList[i];if (sgv.IsPlaying)MasterAudio.StopVariationInSoundGroup(group.GameObjectName, sgv.name);}sgvList.RemoveAll(item => (item.IsPlaying == false || item.VarAudio.clip == null));}public void StopAudioGroup(AudioType audioType, bool isFadeOut = false, float fadeOutTime = 1f){string curPath = GetPlayingPaths(audioType);if (curPath.Equals(""))return;MasterAudioGroup group = GetAudioGroup(audioType);if (audioType == AudioType.BGM){waitingBGM.path = null;}else if (audioType == AudioType.Voice){waitingVoice.path = null;}if (isFadeOut){Coroutine curCor = GetAudioFadeOutCor(audioType);if (curCor == null){SoundGroupVariation curSGV = GetAudioCurVariation(audioType);SetAudioFadeOutCor(audioType, StartCoroutine(FadeOutAndPlayNext(fadeOutTime, audioType)));}else{RealStopAudioGroup(audioType);}}else{RealStopAudioGroup(audioType);}}// todopublic void PauseAudio(AudioType audioType, string path){}public void PauseAudioGroup(AudioType audioType){}public void ResumeAudio(AudioType audioType, string path){}public void ResumeAudioGroup(AudioType audioType){}public void SilentAudioGroup(AudioType audioType, bool bMute){MasterAudioGroup group = GetAudioGroup(audioType);if (bMute)MasterAudio.MuteGroup(group.GameObjectName);elseMasterAudio.UnmuteGroup(group.GameObjectName);}public void SetAudioGroupVolume(AudioType audioType, float volume, bool isGradual = false, float time = 1f){if (volume > 1f) volume = 1f;if (volume < 0f) volume = 0f;MasterAudioGroup group = GetAudioGroup(audioType);if (!isGradual)MasterAudio.SetGroupVolume(group.GameObjectName, volume);elseMasterAudio.FadeSoundGroupToVolume(group.GameObjectName, volume, time);SaveAudioGroupVolume(audioType,volume);}public float GetAudioPlayTime(string path){foreach (SoundGroupVariation sgv in sgvList){if (sgv.GetCurClipName() == path)return sgv.VarAudio.time;}return -1;}public float GetAudioLength(string path){foreach (SoundGroupVariation sgv in sgvList){if (sgv.GetCurClipName() == path)return sgv.VarAudio.clip.length;}return -1;}/// <returns name="path">如有多个,以逗号分隔</returns>public string GetPlayingPaths(AudioType audioType){string paths = "";foreach (SoundGroupVariation sgv in sgvList){if (sgv.ParentGroup == GetAudioGroup(audioType)){if (!paths.Equals(""))paths += ",";paths += sgv.GetCurClipName();}}return paths;}#endregion#region privateprivate bool TryLoadAudio(MasterAudioGroup group, string path){if (path == null){Debug.LogError("传入的文件路径为空");return false;}if (group == null){Debug.LogError("当前没有创建相关的MasterAudioGroup");return false;}if (!LoadAudio(group, path)){Debug.LogError("加载 " + path + " 路径下的资源失败");return false;}return true;}private bool LoadAudio(MasterAudioGroup audioGroup, string clipPath){if (!audioGroup.hasReadyClip(clipPath)){AudioClip cp = GameAssetProxy.Load<AudioClip>(GameAssetType.Audio, clipPath);cp.name = clipPath; // 音频这边以path为keyif (cp == null)return false;audioGroup.ReadyAudioClips.Add(clipPath, cp);}return true;}private void RealPlayAudio(MasterAudioGroup group, string path, bool isloop, string callBack, Vector3 position,float volume = 1f, float speed = 1f, float startTime = 0){PlaySoundResult result;if (position != null && !position.Equals(Vector3.zero))// 对Z轴距离无效result = MasterAudio.PlaySound3DAtVector3(group.GameObjectName, path, position, volume, speed);elseresult = MasterAudio.PlaySound(group.GameObjectName, path, volume, speed);if (result != null){SoundGroupVariation sgv = result.ActingVariation;sgv.VarAudio.loop = isloop;sgv.JumpToTime(startTime);sgvList.Add(sgv);if (callBack != null)StartCoroutine(PlayEndCallBack(sgv, path, callBack));}else{Debug.LogError("播放音效失败!");return;}}private void RealPlayAudio(MasterAudioGroup group, string path, bool isloop, string callBack, Transform trans,float volume = 1f, float speed = 1f, float startTime = 0){PlaySoundResult result;if (trans != null)// 对Z轴有效result = MasterAudio.PlaySound3DFollowTransform(group.GameObjectName, path, trans, volume, 1, 0);elseresult = MasterAudio.PlaySound(group.GameObjectName, path, volume, speed);if (result != null){SetPlaySoundResult(result,path,isloop,callBack,startTime);}else{Debug.LogError("播放音效失败!");return;}}private void SetPlaySoundResult(PlaySoundResult result,string path,bool isloop,string callBack,float startTime = 0){if (result != null){SoundGroupVariation sgv = result.ActingVariation;sgv.VarAudio.loop = isloop;sgv.JumpToTime(startTime);sgvList.Add(sgv);if (callBack != null)StartCoroutine(PlayEndCallBack(sgv, path, callBack)); }}public MasterAudioGroup GetAudioGroup(AudioType audioType){MasterAudioGroup group = null;if (!_masterAudioGroupDic.TryGetValue(audioType, out group)){Debug.LogError($"not find group,audioType:{audioType.ToString()}");}return group;}private SoundGroupVariation GetAudioCurVariation(AudioType audioType){foreach (SoundGroupVariation sgv in sgvList){if (sgv.ParentGroup.name == GetAudioGroup(audioType).name)return sgv;}return null;}private Coroutine GetAudioFadeOutCor(AudioType audioType){switch (audioType){case AudioType.BGM:return audioFadeOutCorBGM;case AudioType.Voice:return audioFadeOutCorVoice;}return null;}private void SetAudioFadeOutCor(AudioType audioType, Coroutine cor){switch (audioType){case AudioType.BGM:audioFadeOutCorBGM = cor;break;case AudioType.Voice:audioFadeOutCorVoice = cor;break;}}private void RealStopAudioGroup(AudioType audioType){MasterAudioGroup group = GetAudioGroup(audioType);MasterAudio.StopAllOfSound(group.GameObjectName);}private PlayAudioArgs GetWaitingArgs(AudioType audioType){if (audioType == AudioType.BGM)return waitingBGM;else if (audioType == AudioType.Voice)return waitingVoice;return new PlayAudioArgs();}private bool AllowFadeOut(AudioType audioType){if (audioType == AudioType.BGM || audioType == AudioType.Voice)return true;return false;}private IEnumerator FadeOutAndPlayNext(float fadeOutTime, AudioType audioType){SoundGroupVariation curSGV = GetAudioCurVariation(audioType);if (curSGV != null){curSGV.FadeOutNow(fadeOutTime);yield return new WaitForSeconds(fadeOutTime);}else{yield return new WaitForSeconds(0.01f);     // 此行仅仅是为了代码方便好写}SetAudioFadeOutCor(audioType, null);RealStopAudioGroup(audioType);if (AllowFadeOut(audioType)){PlayAudioArgs waitingArgs = GetWaitingArgs(audioType);if (waitingArgs.path != null){RealPlayAudio(waitingArgs.group, waitingArgs.path, waitingArgs.isLoop, waitingArgs.callBack, waitingArgs.position, waitingArgs.volume, waitingArgs.speed, waitingArgs.startTime);}}}private IEnumerator PlayEndCallBack(SoundGroupVariation sgv, string path, string callBack){while (sgv != null && sgv.IsPlaying)yield return null;LuaClient.GetMainState().CallLuaFunction(callBack, path);}private void TryUnloadUselessClips(){// todo: 怀疑这里会有"在卸载的同一帧播放音频时播不出来"的bug,但暂时没空自测了List<string> unloadClipNames = new List<string>();foreach (SoundGroupVariation sgv in sgvList){if (!sgv.IsPlaying){string name = sgv.VarAudio.clip.name;if (!unloadClipNames.Contains(name))unloadClipNames.Add(sgv.VarAudio.clip.name);}}foreach (string clipName in unloadClipNames){bool canRemove = true;if (clipName == waitingBGM.path || clipName == waitingVoice.path)canRemove = false;if (canRemove){foreach (SoundGroupVariation sgv in sgvList){if (sgv.VarAudio.isPlaying && sgv.VarAudio.clip && sgv.VarAudio.clip.name == clipName){canRemove = false;break;}}}if (canRemove){List<MasterAudioGroup> audioGroups = new List<MasterAudioGroup>();foreach (SoundGroupVariation sgv in sgvList){if (sgv.VarAudio.clip && sgv.VarAudio.clip.name == clipName){sgv.VarAudio.clip = null;if (!audioGroups.Contains(sgv.ParentGroup))audioGroups.Add(sgv.ParentGroup);}}foreach (MasterAudioGroup audioGroup in audioGroups){AudioClip clip = audioGroup.ReadyAudioClips[clipName];audioGroup.ReadyAudioClips.Remove(clipName);GameAssetProxy.Unload(GameAssetType.Audio, clip);clip = null;}}}sgvList.RemoveAll(item => (item.IsPlaying == false || item.VarAudio.clip == null));}#endregion#region 调整某一大类音效音量private void SaveAudioGroupVolume(AudioType audioType,float volume){PlayerPrefs.SetFloat(audioType.ToString(), volume);}public float GetAudioGroupVolume(AudioType audioType){if(PlayerPrefs.HasKey(audioType.ToString()))return PlayerPrefs.GetFloat(audioType.ToString());return 1;}#endregion
}

音频与场景物体绑定工具:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class AudioClipConfig
{[HideInInspector]public string name = "";public AudioClip clip;public AudioType audioType = AudioType.SE_3D;[Tooltip("路径")] public string path = "";[Tooltip("音量"),Range(0,1)] public float volume = 1;[Tooltip("音高"),Range(0,3)] public float pitch = 1;[Tooltip("播放速度")] public float speed = 1;[Tooltip("是否循环")]public bool loop = false;[Tooltip("显示时播放")]public bool playOnLoad = false;public void Reset(){name = string.Empty;clip = null;audioType = AudioType.SE_3D;path = "";volume = 1;speed = 1;pitch = 1;playOnLoad = false;}
}public class GameObjectAudioConfig : MonoBehaviour
{[Header("隐藏时停止")]public bool hideStopAudio = true;public List<AudioClipConfig> audioClipConfigList = new List<AudioClipConfig>();// Start is called before the first frame updatevoid OnEnable(){StartCoroutine(_PlayOnLoad());}private void OnDisable(){if(hideStopAudio)Stop();}public void Play(){if (AudioSystem.Instance == null){Debug.LogError("AudioSystem not init");return;}for (int i = 0; i < audioClipConfigList.Count; i++){AudioClipConfig config = audioClipConfigList[i];_Play(config);}}public void Stop(){if (AudioSystem.Instance == null){return;}for (int i = 0; i < audioClipConfigList.Count; i++){AudioClipConfig config = audioClipConfigList[i];AudioSystem.Instance.StopAudio(config.audioType,config.path);}}private IEnumerator _PlayOnLoad(){while (AudioSystem.Instance == null){yield return null;}for (int i = 0; i < audioClipConfigList.Count; i++){AudioClipConfig config = audioClipConfigList[i];if (config.playOnLoad){_Play(config);}}}private void _Play(AudioClipConfig config){if (config.audioType == AudioType.SE_3D)// AudioSystem.Instance.PlaySound3DAtTransform(config.audioType, config.path, transform, config.volume, config.loop);AudioSystem.Instance.PlaySound3DFollowTransform(config.audioType, config.path, transform, config.volume, config.loop);else{AudioSystem.Instance.PlayAudio(config.audioType, config.path, config.volume, config.loop, false, 0,null, config.speed, 0, transform.position.x, transform.position.y, transform.position.z);}   }}

Editor文件夹下的编辑器脚本:


using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;[CustomEditor(typeof(GameObjectAudioConfig))]
public class GameObjectAudioConfigEditor:Editor
{private List<AudioClipConfig> audioClipConfigList;private void Awake(){GameObjectAudioConfig config = target as GameObjectAudioConfig;audioClipConfigList = config.audioClipConfigList;}public override void OnInspectorGUI(){for (int i = 0; i < audioClipConfigList.Count; i++){var config = audioClipConfigList[i];if (config.clip == null){config.Reset();}string path = config.clip == null ? string.Empty : AssetDatabase.GetAssetPath(config.clip);config.path = path == string.Empty ? string.Empty : GetAudioPath(path);config.name = path == string.Empty ? string.Empty : Path.GetFileNameWithoutExtension(path);}base.OnInspectorGUI();}private string GetAudioPath(string path){string _path = path.Replace(Path.GetExtension(path), String.Empty);return _path.Replace("Assets/Resources/", string.Empty);}
}

脚步声配置工具:这里使用不用的Layer播放不同的音效

/** 脚步声单元* 2022.11.9* linYiShan*/
using System;
using System.Collections.Generic;
using DarkTonic.MasterAudio;
using UnityEngine;public class FootstepSoundsUnit:MonoBehaviour
{public enum SoundSpawnLocationMode {MasterAudioLocation,    // 主音频位置:任何声音组都将从主音频的位置发出CallerLocation,         // 呼叫者位置:这将从该游戏对象的位置触发声音组AttachToCaller          // 附加到呼叫者:默认值。这实际上不会重新设置Variation游戏对象,但它将遵循具有 Event Sounds 脚本的游戏对象的位置。这样,当物体消失或被场景更改破坏时,声音不会被切断或变化对象被破坏。}public enum FootstepTriggerMode {None,OnCollisionEnter,OnCollisionExit,OnTriggerEnter,OnTriggerExit,OnCollision2D,OnTriggerEnter2D}[Header("声音生成模式")]public SoundSpawnLocationMode soundSpawnMode = SoundSpawnLocationMode.CallerLocation;[Header("脚步声触发事件")]public FootstepTriggerMode footstepEvent = FootstepTriggerMode.OnTriggerEnter;[Header("限制触发间距模式")]public EventSounds.RetriggerLimMode retriggerLimitMode = EventSounds.RetriggerLimMode.FrameBased;[Header("显示帧数")]public int limitPerXFrm = 10000;[Header("限制秒数")]public float limitPerXSec = 0f;[HideInInspector]public int triggeredLastFrame = -100;[HideInInspector]public float triggeredLastTime = -100f;// ReSharper restore InconsistentNaming[HideInInspector,Header("使用层筛选")]public bool useLayerFilter = true;[HideInInspector,Header("使用标签筛选")]    // 暂不使用public bool userTagFilter = false;[Header("脚步声音频")]public List<FootStepAudioInfo> footstepAudioInfoList = new List<FootStepAudioInfo>();private Transform _trans;private void Start(){}private double t = 0;// ReSharper disable once UnusedMember.Localprivate void OnTriggerEnter(Collider other) {if (footstepEvent != FootstepTriggerMode.OnTriggerEnter) {return;}PlaySoundsIfMatch(other.gameObject);}private void OnTriggerExit(Collider other){if (footstepEvent != FootstepTriggerMode.OnTriggerExit) {return;}PlaySoundsIfMatch(other.gameObject);}// ReSharper disable once UnusedMember.Localprivate void OnCollisionEnter(Collision collision) {if (footstepEvent != FootstepTriggerMode.OnCollisionEnter) {return;}PlaySoundsIfMatch(collision.gameObject);}private void OnCollisionExit(Collision collision){if (footstepEvent != FootstepTriggerMode.OnCollisionExit) {return;}PlaySoundsIfMatch(collision.gameObject);}// ReSharper disable once UnusedMember.Localprivate void OnCollisionEnter2D(Collision2D collision) {if (footstepEvent != FootstepTriggerMode.OnCollision2D) {return;}PlaySoundsIfMatch(collision.gameObject);}// ReSharper disable once UnusedMember.Localprivate void OnTriggerEnter2D(Collider2D other) {if (footstepEvent != FootstepTriggerMode.OnTriggerEnter2D) {return;}PlaySoundsIfMatch(other.gameObject);}private bool CheckForRetriggerLimit() {// check for limiting restraintsswitch (retriggerLimitMode) {case EventSounds.RetriggerLimMode.FrameBased:if (triggeredLastFrame > 0 && AudioUtil.FrameCount - triggeredLastFrame < limitPerXFrm) {return false;}break;case EventSounds.RetriggerLimMode.TimeBased:if (triggeredLastTime > 0 && AudioUtil.Time - triggeredLastTime < limitPerXSec) {return false;}break;}return true;}private void PlaySoundsIfMatch(GameObject go) {if (!CheckForRetriggerLimit()) {return;}// set the last triggered time or frameswitch (retriggerLimitMode) {case EventSounds.RetriggerLimMode.FrameBased:triggeredLastFrame = AudioUtil.FrameCount;break;case EventSounds.RetriggerLimMode.TimeBased:triggeredLastTime = AudioUtil.Time;break;}// ReSharper disable once ForCanBeConvertedToForeachfor (var i = 0; i < footstepAudioInfoList.Count; i++) {var aGroup = footstepAudioInfoList[i];// check filters for matches if turned onif (useLayerFilter && !aGroup.layerMatchs.Contains(go.layer)) {continue;}if (userTagFilter && !aGroup.tagMatchs.Contains(go.tag)) {continue;}var volume = aGroup.volume;float pitch = aGroup.pitch;switch (soundSpawnMode) {case SoundSpawnLocationMode.CallerLocation:AudioSystem.Instance.PlaySound3DAtTransform(AudioType.Footstep,aGroup.path,Trans,volume,false,pitch);break;case SoundSpawnLocationMode.AttachToCaller:AudioSystem.Instance.PlaySound3DFollowTransform(AudioType.Footstep,aGroup.path,Trans,volume,false,pitch);break;case SoundSpawnLocationMode.MasterAudioLocation:AudioSystem.Instance.PlayAudio(AudioType.Footstep,aGroup.path,volume,false);break;}}}private Transform Trans {get {if (_trans != null) {return _trans;}_trans = transform;return _trans;}}
}[Serializable]
public class FootStepAudioInfo
{[HideInInspector]public string name = "";public AudioClip clip = null;[Tooltip("路径")] public string path = "";[Tooltip("音量"),Range(0,1)] public float volume = 1;[Tooltip("音高"),Range(0,3)] public float pitch = 1;[Header("层筛选"), LayerPropertyAttribute]public List<int> layerMatchs = null;[HideInInspector,Header("标签筛选"), TagPropertyAttribute]public List<string> tagMatchs = null;public void Reset(){name = string.Empty;clip = null;path = "";volume = 1;pitch = 1;layerMatchs = null;tagMatchs = null;}
}public class LayerPropertyAttribute:PropertyAttribute {}
public class TagPropertyAttribute:PropertyAttribute {}

Editor文件夹下的编辑器脚本:

FootstepSoundsUnitEditor:
using System;
using System.Collections.Generic;
using System.IO;
using DarkTonic.MasterAudio;
using UnityEditor;[CustomEditor(typeof(FootstepSoundsUnit))]
public class FootstepSoundsUnitEditor:Editor
{private List<FootStepAudioInfo> footStepAudioInfoList;private void Awake(){FootstepSoundsUnit config = target as FootstepSoundsUnit;footStepAudioInfoList = config.footstepAudioInfoList;}public override void OnInspectorGUI(){for (int i = 0; i < footStepAudioInfoList.Count; i++){var config = footStepAudioInfoList[i];if (config.clip == null){config.Reset();}string path = config.clip == null ? string.Empty : AssetDatabase.GetAssetPath(config.clip);config.path = path == string.Empty ? string.Empty : GetAudioPath(path);config.name = path == string.Empty ? string.Empty : Path.GetFileNameWithoutExtension(path);}base.OnInspectorGUI();}private string GetAudioPath(string path){string _path = path.Replace(Path.GetExtension(path), String.Empty);return _path.Replace("Assets/Resources/", string.Empty);}
}
using UnityEditor;
using UnityEngine;[CustomPropertyDrawer(typeof(LayerPropertyAttribute))]
public class LayerPropertyDrawer : PropertyDrawer
{public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){// LayerPropertyAttribute info = base.attribute as LayerPropertyAttribute;property.intValue = EditorGUI.LayerField(position,"layer Match ", property.intValue);}
}[CustomPropertyDrawer(typeof(TagPropertyAttribute))]
public class TagPropertyDrawer : PropertyDrawer
{public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){// TagPropertyAttribute info = base.attribute as TagPropertyAttribute;property.stringValue = EditorGUI.TagField(position,"tag Match ", property.stringValue);}
}

Unity 音频插件 - MasterAudio 实现音频管理系统相关推荐

  1. unity中使用fmod音频插件1

    1.安装音频编辑软件 插件下载网址:https://www.fmod.com/download fmod api网址:https://www.fmod.com/resources/documentat ...

  2. audio unity 加速_浅谈Unity中Android、iOS音频延迟

    在Unity上面做音游,当在移动端实机运行起来,会发现,音频的发出会有一定的延迟,无论是长音效还是短音效,Unity内置的Audio内部使用的是FMOD,有以下手段改善 通过设置稍微改善其延迟的问题 ...

  3. 关于使用3D音频插件过程中失声问题

    大家好,今天小白给大家简单分享下我在使用高通3D音频插件过程中遇到的更改音频设置就不会产生声音的问题及其解决方式,欢迎一起学习交流. 一.问题描述 我使用的Unity版本是2018.3.1.9f1,由 ...

  4. 使用Unity5开发手游,使用FMOD或wwise音频插件而不是自带的声音系统有哪些好处?

    使用Unity5开发手游,使用FMOD或wwise音频插件而不是自带的声音系统有哪些好处? https://www.zhihu.com/question/61882604 碰巧对Unity里的声音脚本 ...

  5. au vst插件_失真效果音频插件

    iZotope Trash 2 Mac版是一款可以在苹果电脑MAC OS平台上使用的具有64bit处理制造失真效果的音频插件.iZotope Trash 2 可以对任何音频文件进行失真效果的处理,现为 ...

  6. Arturia Prophet Mac音频插件:将Prophet 5,Prophet VS,Prophet Hybrid三种不同音乐合成器于一体

    Prophet 5和Prophet VS设定了标准并重新定义了现代合成器.我们为您带来了这些经典. Prophet 5是市场上第一款完全可编程的合成器.迄今为止,这种革命性合成器已成为所有其他合成器的 ...

  7. flstudio插件找不到_【干货】音频插件完全指引手册

    本文适合于音乐制作初学者.和有一定经验但仍希望查漏补缺的音乐人朋友们.希望通过本文,帮助大家全面.系统.通俗易懂地了解音频插件,并知道如何选择. 什么是音频插件 随着时代进步,现代音乐制作已广泛采用P ...

  8. JavaScript 音频插件和图表插件

    howler音频插件 配置项及事件 <!DOCTYPE html> <html lang="en"> <head><meta charse ...

  9. Unity 进阶 之 实现简单的音频可视化封装(包括音频和麦克风)

    Unity 进阶 之 实现简单的音频可视化封装(包括音频和麦克 目录 Unity 进阶 之 实现简单的音频可视化封装(包括音频和麦克 一.简单介绍 二.实现原理 三.注意事项 四.效果预览 五.实现步 ...

最新文章

  1. LeetCode 76. Minimum Window Substring / 567. Permutation in String
  2. c++封装继承多态实例
  3. ThinkPHP如何判断一个更新操作是否成功
  4. 块存储,文件存储和对象存储
  5. SpringMVC配置视图的直接映射view-controller命名空间
  6. 如何在windows下成功的编译和安装python组件hyperscan
  7. linux ftdi 虚拟,linux – 由FTDI USB串行转换器创建的监控(嗅探)/ dev / ttyUSB0
  8. 信息学奥赛一本通|1183:病人排队
  9. html5 sketchpad,Sketchpad:基于html5在线图像绘画板
  10. 区块链入门教程(8)--WeBASE-Front节点前置服务
  11. Python——类(class)的定义及使用
  12. miui android耗电快,你们的小米手机更新MIUI10之后耗电吗?试试这个方法解决吧
  13. 酷炫的JS特效(转载)
  14. 操作excel文件爬取nvd.nist数据
  15. ResNet论文翻译及解读
  16. 工业触控一体机的特点和优势
  17. 全国、县区级行政区高程和坡度参数计算结果数据
  18. 什么是真正的需求,如何才能找到?
  19. 2021年熔化焊接与热切割考试技巧及熔化焊接与热切割操作证考试
  20. 在google drive使用google.colab云服务

热门文章

  1. Banana Pi开源社区开源硬件瑞芯微RK3568/RK3588全国产化支持计划
  2. 盘点2019十大科技并购:IBM收购红帽居首,阿里考拉仅排第十;英特尔20亿美元收购Habana Labs;柳传志将卸任联想……...
  3. 【已解决】第一次遇到无法新建APP问题
  4. 有关计算机专业的自荐信英文,计算机专业英文自荐信
  5. geohash java github_geohash
  6. 集中式版本控制 VS 分布式版本控制
  7. html 怎样设置按钮的位置
  8. mysql 找表重复数据,mysql 数据表中查找重复记录
  9. walking机器人入门教程-深度学习-使用yolov5进行物体识别
  10. SpringBoot拦截器失效问题excludePathPatterns失效问题