插件介绍:
Master Audio的是一个整体解决方案,所有的丰富的游戏音频需求。内置的音乐闪避,手动和自动的声音触发真正的随机声音变化,音频汇集全3D声音功能。支持所有出口的手机游戏平台,具有一流的性能。
主音频在线帮助网站可在此处找到:
Table of Contents
完整的主音频 API 文档可在此处找到:
Master Audio - AAA Sound Solution!: Main Page
实现功能:
这里不细说实现中使用MasterAudio插件的API了(可以直接去翻一下插件文档)。
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
- _masterAudioGroupDic = new Dictionary
(); -
- 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
sgvList = new List(); -
- #endregion
-
- #region 初始化相关
-
- //初始化使用到的MasterAudio音乐组件
- public void Awake()
- {
- GameObject Masterad = new GameObject("MasterAudio");
- if (Masterad != null)
- {
- DontDestroyOnLoad(Masterad);
- } //加载时不销毁此GameObject
-
- masterAudio = Masterad.AddComponent
(); -
- //设置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
(); - if (audioGroup == null)
- {
- audioGroup = trans.gameObject.AddComponent
(); - }
-
- audioGroup.groupMasterVolume = GetAudioGroupVolume(audioType);
- return audioGroup;
- }
-
- float deltaTime = 0f;
-
- public void LateUpdate()
- {
- deltaTime += Time.deltaTime;
- if (deltaTime >= unloadTime)
- {
- deltaTime = 0f;
- TryUnloadUselessClips();
- }
- }
-
- #endregion
-
- #region 开放方法
-
- ///
- /// 播放音效
- ///
- /// 音效组类型
- /// 音效路径
- /// 音量[0, 1] (仅该音效的音量,不指音效组总音量)
- /// 是否循环播放
- /// 播放完毕回调
- /// 播放速度
- /// 是否淡出
- /// 淡出时长
- /// 3D音效的位置
- /// 3D音效的位置
- /// 3D音效的位置
- 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);
- }
- }
-
- // todo
- public 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);
- else
- MasterAudio.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);
- else
- MasterAudio.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;
- }
-
- ///
如有多个,以逗号分隔 - 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 private
-
- private 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
(GameAssetType.Audio, clipPath); - cp.name = clipPath; // 音频这边以path为key
- if (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);
- else
- result = 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);
- else
- result = 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
audioGroups = new List(); - 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
- }
- /*
- * 物体与声音绑定配置表
- * 2022.11.9
- * linYiShan
- */
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using DarkTonic.MasterAudio;
- using MainCameraSpace;
- using UnityEditor;
- 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;
- [Tooltip("范围")]
- public float range = 30;
-
- [HideInInspector] public bool isPlaying = false;
- [HideInInspector] public SoundGroupVariation variation = null;
-
- public void Reset()
- {
- name = string.Empty;
- clip = null;
- audioType = AudioType.SE_3D;
- path = "";
- volume = 1;
- speed = 1;
- pitch = 1;
- playOnLoad = false;
- range = 30;
- }
- }
-
- public class GameObjectAudioConfig : MonoBehaviour
- {
- // 编辑器范围显示
- public static bool ShowRange = false;
- [Header("隐藏时停止播放")]
- public bool hideStopAudio = true;
- [Header("声音曲线")]
- public AnimationCurve audioVolumeCurve = AnimationCurve.Linear(0, 0, 1, 1);
- [Header("声音列表")]
- public List
audioClipConfigList = new List(); -
- private void Start()
- {
- CreateRangeObj();
- }
-
- // Start is called before the first frame update
- void OnEnable()
- {
- StartCoroutine(_PlayOnLoad());
- }
-
- private void OnDisable()
- {
- if(hideStopAudio)
- Stop();
- }
-
- private void Update()
- {
- DetectionDistance();
- UpdateVolume();
- }
-
- 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];
- _Stop(config);
- }
- }
-
- private void _Stop(AudioClipConfig config)
- {
- if (config.isPlaying)
- {
- if (config.variation != null)
- {
- AudioSystem.Instance.StopAudioBySgvName(config.audioType,config.variation.name);
- config.isPlaying = false;
- config.variation = null;
- }
- // else
- // {
- // AudioSystem.Instance.StopAudio(config.audioType,config.path);
- // Debug.Log("stop audio: " + config.path);
- // config.isPlaying = false;
- // }
- }
- }
-
- private IEnumerator _PlayOnLoad()
- {
- while (AudioSystem.Instance == null)
- {
- yield return null;
- }
-
- for (int i = 0; i < audioClipConfigList.Count; i++)
- {
- AudioClipConfig config = audioClipConfigList[i];
- if(config.audioType == AudioType.SE_3D) continue;
- if (config.playOnLoad)
- {
- _Play(config);
- }
- }
- }
-
- private void _Play(AudioClipConfig config)
- {
- if (config.isPlaying) return;
-
- // if (config.audioType == AudioType.SE_3D)
- // {
- config.variation = AudioSystem.Instance.PlayGameObjectConfigAudio(config.audioType, config.path,1, config.loop);
- if(config.variation == null) return;
- config.isPlaying = true;
- // }
- // else
- // {
- // AudioSystem.Instance.PlayAudio(config.audioType,config.path,config.volume,config.loop);
- // config.isPlaying = true;
- // Debug.Log("play audio: " + config.path);
- // }
- // AudioSystem.Instance.PlaySound3DFollowTransform(config.audioType, config.path, transform, config.volume, config.loop);
- }
-
- private bool CheckInRange(float range)
- {
- // var p = GetCameraLookAtGroundPos();
- var p = AudioSystem.Instance.Scene3DTriggerTrans.position;
- if (Vector3.Distance(p, transform.position) >= range) return false;
- return true;
- }
-
- private void DetectionDistance()
- {
- if (AudioSystem.Instance == null) return;
- if (AudioSystem.Instance.Scene3DTriggerTrans == null) return;
- if(audioClipConfigList == null) return;
-
- for (int i = 0; i < audioClipConfigList.Count; i++)
- {
- var cfg = audioClipConfigList[i];
- if(cfg.audioType != AudioType.SE_3D) continue;
-
- if (CheckInRange(cfg.range))
- {
- if (!cfg.isPlaying)
- {
- _Play(cfg);
- }
- }
- else
- {
- if (cfg.isPlaying)
- {
- _Stop(cfg);
- }
- }
- }
- }
-
- public Vector3 GetCameraLookAtGroundPos()
- {
- Transform camera = MainCameraController.GetInstance().GetMainCameraTransform();
- Vector3 p = GetIntersectWithLineAndPlane(camera.position,camera.forward,new Vector3(0,1,0), new Vector3(0,transform.position.y,9));
- return p;
- }
-
- ///
- /// 计算直线与平面的交点
- ///
- /// 直线上某一点
- /// 直线的方向
- /// 垂直于平面的的向量
- /// 平面上的任意一点
- ///
- private Vector3 GetIntersectWithLineAndPlane(Vector3 point, Vector3 direct, Vector3 planeNormal, Vector3 planePoint)
- {
- float d = Vector3.Dot(planePoint - point, planeNormal) / Vector3.Dot(direct.normalized, planeNormal);
- return d * direct.normalized + point;
- }
-
- private void UpdateVolume()
- {
- if (AudioSystem.Instance == null) return;
- if (AudioSystem.Instance.Scene3DTriggerTrans == null) return;
-
- for (int i = 0; i < audioClipConfigList.Count; i++)
- {
- AudioClipConfig config = audioClipConfigList[i];
- if(config.audioType != AudioType.SE_3D) continue;
-
- if (config.isPlaying)
- {
- float dis = Vector3.Distance(AudioSystem.Instance.Scene3DTriggerTrans.position, transform.position) / (config.range);
- dis = 1 - Math.Min(dis, 1);
- float volume = audioVolumeCurve.Evaluate(dis);
- volume = volume * config.volume;
- // MasterAudioGroup group = AudioSystem.Instance.GetAudioGroup(config.audioType);
- if (config.variation != null)
- {
- // MasterAudio.ChangeVariationVolume(group.GameObjectName,true,config.variation.name,volume);
- config.variation.VarAudio.volume = volume;
- }
- }
- }
- }
-
- public void CreateRangeObj()
- {
- #if UNITY_EDITOR
- if(!GameObjectAudioConfig.ShowRange) return;
-
- Transform audioTrans = transform.Find("AuidoRange");
- if (audioTrans == null)
- {
- GameObject obj = new GameObject("AuidoRange");
- obj.transform.SetParent(transform);
- audioTrans = obj.transform;
- audioTrans.localScale = new Vector3(1,1,1);
- audioTrans.localPosition = new Vector3();
- }
- var spherePrefab = EditorGUIUtility.LoadRequired("Assets/Resources/Editor/Audio/Sphere.prefab") as GameObject;
- for (int i = 0; i < audioClipConfigList.Count; i++)
- {
- var config = audioClipConfigList[i];
- if(config.clip == null) continue;
- Transform child = audioTrans.Find(config.name);
- if (child == null)
- {
- var obj = Instantiate(spherePrefab, audioTrans);
- obj.name = config.name;
- child = obj.transform;
- }
- float radius = config.range * 2;
- child.localScale = new Vector3(radius, radius, radius);
- child.localPosition = new Vector3();
- }
- #endif
- }
- }
Editor文件夹下的编辑器脚本:
-
- using System;
- using System.Collections.Generic;
- using System.IO;
- using UnityEditor;
-
- [CustomEditor(typeof(GameObjectAudioConfig))]
- public class GameObjectAudioConfigEditor:Editor
- {
- private List
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);
- }
- }
- /*
- * 脚步声单元
- * 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
footstepAudioInfoList = new List(); -
- private Transform _trans;
-
- private void Start()
- {
-
- }
-
- private double t = 0;
- // ReSharper disable once UnusedMember.Local
- private 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.Local
- private 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.Local
- private void OnCollisionEnter2D(Collision2D collision) {
- if (footstepEvent != FootstepTriggerMode.OnCollision2D) {
- return;
- }
-
- PlaySoundsIfMatch(collision.gameObject);
- }
-
- // ReSharper disable once UnusedMember.Local
- private void OnTriggerEnter2D(Collider2D other) {
- if (footstepEvent != FootstepTriggerMode.OnTriggerEnter2D) {
- return;
- }
-
- PlaySoundsIfMatch(other.gameObject);
- }
-
- private bool CheckForRetriggerLimit() {
- // check for limiting restraints
- switch (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 frame
- switch (retriggerLimitMode) {
- case EventSounds.RetriggerLimMode.FrameBased:
- triggeredLastFrame = AudioUtil.FrameCount;
- break;
- case EventSounds.RetriggerLimMode.TimeBased:
- triggeredLastTime = AudioUtil.Time;
- break;
- }
-
- // ReSharper disable once ForCanBeConvertedToForeach
- for (var i = 0; i < footstepAudioInfoList.Count; i++) {
- var aGroup = footstepAudioInfoList[i];
-
- // check filters for matches if turned on
- if (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 {}
FootstepSoundsUnitEditor:
- using System;
- using System.Collections.Generic;
- using System.IO;
- using DarkTonic.MasterAudio;
- using UnityEditor;
-
- [CustomEditor(typeof(FootstepSoundsUnit))]
- public class FootstepSoundsUnitEditor:Editor
- {
- private List
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);
- }
- }