之前做过的大大小小的项目,都会涉及到声音资源的播放,虽然播放声音片段技术含量不高,几步就能搞定,但如果每次建项目都需要写个声音播放类也比较麻烦,不同的项目可能也有不同的功能要求,有的只需要播放就行,再就是每次写的若有针对性,以后回看代码会降低效率,所以就把我以前所使用到的功能集合到一起,把声音播放功能做成一个预制体,即方便使用,也能统一方法。主要能实现声音的播放,暂停,停止,缓存,音量调节,循环,是否覆盖,播放完成回调等功能,后面若接触到新的需要还会继续添加迭代。
制作思路也比较简单,就是将音频播放分为不同的类型,如背景音,特效音,人物语言等等,每个类型的音频用一个AudioSourece播放,然后在播放的时候需要指出播放那个类型的音频,以及播放音频的文件名。
使用方式如下:
1,新建空组件GameObject(不限定),添加AudioPlayer脚本
2,约定一个音效类型(代码中会根据类型播放),如:bg,然后指定他的资源路径,最后点击“添加播放器”
点击后,GameObject下会出现一个子物体,名字是AS(audiosource)+你约定的音频类型名称,然后会自动挂上了AudioSource组件,挂上了本组件的配置信息脚本
3,使用方式如下:前两个参数是必填项,一个是播放声音的片段类型,他决定了在哪个AudioSource上面播放,第二个是声音片段的文件名
播放完成监听(每个使用类设置一个就行,不需要针对每个声音片段设置):需要将播放方法的是否监听设置为ture,然后该声音片段播发完成后result就能返回该片段名称
下面是AudioPlayer的源码,调用AudioPlay()方法进行播放,可以设置是否缓存,音量,是否循环,是否覆盖(若已经在播放该片段的情况下),播放完成后是否需要反馈。后面可调用方法分别是停止,暂停,继续播放,传入相应的声音类型即可。
public class AudioPlayer : MonoBehaviour
{
private static AudioPlayer _audioPlayer;
private List<AudioItem> audioClasses;
//public List<AudioOverListener> audioOverListeners;
//public delegate void AudioOverListener(string name);
public Action<string> AudioOverAction;
private void Awake()
{
_audioPlayer = this.GetComponent<AudioPlayer>();
audioClasses = new List<AudioItem>();
foreach (Transform child in transform)
{
AudioItem audioItem = child.GetComponent<AudioItem>();
audioClasses.Add(new AudioItem(audioItem.ResourceType, audioItem.ResourcePath, audioItem.ItemAudioSource));
}
}
public static AudioPlayer GetInstance()
{
return _audioPlayer;
}
/// <summary>
/// 播放声音片段方法
/// </summary>
/// <param name="type">类型</param>
/// <param name="audioName">片段名称</param>
/// <param name="cache">是否缓存</param>
/// <param name="volume">音量</param>
/// <param name="isLoop">是否循环</param>
/// <param name="isCover">是否覆盖</param>
/// <param name="isOverListener">是否需要播放完成回调监听</param>
public void AudioPlay(string type, string audioName, bool cache = false, bool isLoop = false, bool isCover = true, bool isOverListener = false, float volume = 1)
{
foreach (AudioItem child in audioClasses)
{
if (child.ResourceType.Equals(type))
{
AudioClip ac;
if (!child.AudioDic.TryGetValue(audioName, out ac))
{
ac = Resources.Load<AudioClip>(child.ResourcePath + "/" + audioName);
if (cache)
{
child.AudioDic.Add(audioName, ac);
}
}
else
{
ac = child.AudioDic[audioName];
}
if (child.ItemAudioSource != null)
{
if (!isCover && child.ItemAudioSource.isPlaying)
{
if (child.ItemAudioSource.clip.name.Equals(audioName)) return;
}
child.ItemAudioSource.clip = ac;
child.ItemAudioSource.loop = isLoop;
child.ItemAudioSource.volume = volume;
child.ItemAudioSource.Play();
if (isOverListener)
StartCoroutine(PlayBack(ac.name, ac.length));
}
break;
}
}
}
private IEnumerator PlayBack(string name, float length)
{
yield return new WaitForSeconds(length);
AudioOverAction(name);
}
/// <summary>
/// 结束
/// </summary>
/// <param name="type">音频类型</param>
public void Stop(string type)
{
foreach (AudioItem child in audioClasses)
{
if (child.ResourceType.Equals(type))
{
if (child.ItemAudioSource != null && child.ItemAudioSource.isPlaying)
{
child.ItemAudioSource.Stop();
}
}
}
}
/// <summary>
/// 暂停
/// </summary>
/// <param name="type">音频类型</param>
public void Pause(string type)
{
foreach (AudioItem child in audioClasses)
{
if (child.ResourceType.Equals(type))
{
if (child.ItemAudioSource != null && child.ItemAudioSource.isPlaying)
{
child.ItemAudioSource.Pause();
}
}
}
}
/// <summary>
/// 继续播放
/// </summary>
/// <param name="type">音频类型</param>
public void Restart(string type)
{
foreach (AudioItem child in audioClasses)
{
if (child.ResourceType.Equals(type))
{
if (child.ItemAudioSource != null)
{
child.ItemAudioSource.Play();
Debug.Log("继续播放");
}
}
}
}
}
下面是音频播放器Item属性,用来存放每个类型的播放器配置
/// <summary>
/// 音频播放器Item属性
/// </summary>
[Serializable]
public class AudioItem : MonoBehaviour
{
[SerializeField]
private string resourceType;
[SerializeField]
private string resourcePath;
[SerializeField]
private AudioSource audioSource;
[HideInInspector]
private Dictionary<string, AudioClip> audioDic;
private Action<string> audioOverAction;
#region
public AudioItem(string type, string path, AudioSource audios)
{
ResourceType = type;
ResourcePath = path;
ItemAudioSource = audios;
audioDic = new Dictionary<string, AudioClip>();
}
public string ResourceType
{
get
{
return resourceType;
}
set
{
resourceType = value;
}
}
public string ResourcePath
{
get
{
return resourcePath;
}
set
{
resourcePath = value;
}
}
public AudioSource ItemAudioSource
{
get
{
return audioSource;
}
set
{
audioSource = value;
}
}
public Dictionary<string, AudioClip> AudioDic
{
get
{
return audioDic;
}
set
{
audioDic = value;
}
}
#endregion
}
最后是音频播放器item生成工具,就是前面配置类型和路径然后点击“添加播放器”按钮生成子播放器的工具类
/// <summary>
/// 音频播放器item生成工具
/// </summary>
[CustomEditor(typeof(AudioPlayer))]
public class AddAudioPalyerItem : Editor
{
private static AddAudioPalyerItem _addAudioPalyerItem;
public AddAudioPalyerItem GetInstance()
{
if (_addAudioPalyerItem == null)
{
_addAudioPalyerItem = new AddAudioPalyerItem();
}
return _addAudioPalyerItem;
}
private string typeText;
private string pathText;
/// <summary>
/// <param name="音效类型">播放音效时需按指定类型播放,如bg,player等</param>
/// <param name="资源路径">Resources下声音片段的具体路径文件夹,同个类型的音效放入同个资源路径</param>
/// </summary>
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
typeText = EditorGUILayout.TextField("音效类型:", typeText);
pathText = EditorGUILayout.TextField("资源路径:", pathText);
if (isValue(typeText) & isValue(pathText))
{
if (GUILayout.Button("添加播放器"))
{
GameObject go = new GameObject();
go.name = "AS_" + typeText;
go.AddComponent<AudioSource>().playOnAwake = false;
go.transform.parent = Selection.activeTransform;
go.AddComponent<AudioItem>();
go.GetComponent<AudioItem>().ResourcePath = pathText;
go.GetComponent<AudioItem>().ResourceType = typeText;
go.GetComponent<AudioItem>().ItemAudioSource = go.GetComponent<AudioSource>();
typeText = "";
pathText = "";
}
}
}
private bool isValue(string str)
{
if (str == null | str.Equals(""))
{
return false;
}
else
{
return true;
}
}
}
最后给出导出的unitypackage工具包百度网盘地址,是用unity2017.3.1导出的