解决了 音效模块一 的缺点(只有一个播放器audiosource)
利用有限个播放器(audiosource)管理无限个音效片段(clip)
注释:
- 从设计思路考虑 首先实现简单的SourceManager
- 用对象池设计模式方便动态扩容
- 大概有以下几个功能:
- 在众多播放器里拿出空闲的播放器( AudioSource)
- 播放一个音效(Clip)
- 停止播放一个音效(Clip)
- 释放多余的播放器(AudioSource)
using System.Collections.Generic;
using UnityEngine;
public class SourceManager {
//-----------------------------字段,属性,引用---------------------------------
//播放器个数 初始化为两个
private const int AudioSourceCount = 2;
///
/// 所有播放器的集合
///
List<AudioSource> m_allSources;
///
/// 用于保存释放的临时list
///
/// 实际类型是播放器
List<AudioSource> m_tmpSources = new List<AudioSource> ();
GameObject go;
//=============================================================================
//---------------------------------构造函数-------------------------------------
///
/// 构造函数
///
/// /// 游戏对象
public SourceManager (GameObject _tmpGo) {
this.go = _tmpGo;
Initial ();
}
//=============================================================================
//---------------------------------初始化播放器----------------------------------
///
/// 初始化allSources集合
///
public void Initial () {
m_allSources = new List<AudioSource> ();
for (int i = 0; i < AudioSourceCount; i++) {
AudioSource tmpSource = go.AddComponent<AudioSource> (); //对象挂载音效组件
m_allSources.Add (tmpSource); //存2个音效组件
}
}
//=============================================================================
//---------------------------------获取空闲播放器---------------------------------
///
/// 获取空闲播放器
///
/// 返回 AudioSource
public AudioSource GetFreeAudio () {
//循环找到空闲的
for (int i = 0; i < m_allSources.Count; i++) {
if (!m_allSources[i].isPlaying)
return m_allSources[i];
}
//如果上面循环完没找到就动态创建一个
AudioSource tmpSource = go.AddComponent<AudioSource> ();
m_allSources.Add (tmpSource);
return tmpSource;
}
//=============================================================================
//--------------------------------释放空闲的播放器--------------------------------
///
/// 释放空闲的播放器
///
public void ReleaseFreeAudio () {
int tmpCount = 0;
/*从m_allSources里找空闲放到tmp里准备删除
这里必须要单独存出来 不能直接在循环里面删*/
for (int i = 0; i < m_allSources.Count; i++) {
if (!m_allSources[i].isPlaying) { //空闲一个就计数
tmpCount++;
if (tmpCount > AudioSourceCount) { //默认是2个多了就删
m_tmpSources.Add (m_allSources[i]);
}
}
}
//删all里面播放器 数据是从上面那个循环拿到的
for (int i = 0; i < m_tmpSources.Count; i++) {
AudioSource tmpSource = m_tmpSources[i];
//从m_allSources中移除
m_allSources.Remove (tmpSource);
//从场景中移除组件
GameObject.Destroy (tmpSource);
}
//本次函数走完会清空所有数据 ,确保没有对象再引用 防止没被删完
m_tmpSources.Clear ();
}
//=============================================================================
//----------------------------------停止播放------------------------------------
public void Stop (string _audioName) {
for (int i = 0; i < m_allSources.Count; i++) {
if (m_allSources[i].isPlaying && m_allSources[i].clip.name.Equals (_audioName))
m_allSources[i].Stop ();
}
}
//=============================================================================
}
接下来实现ClipManager
大概功能有:
- 存储所有的Clip - - 这里可以单独写一个类来存
- 从配置文件读取音效名
- 动态添加所有音效并存储
using System.IO;
using UnityEngine;
public class ClipManager {
string[] m_clipName;
SingleClip[] m_allSingleClip;//用单独一个类来存储
public ClipManager () {
ReadConfig ();
LoadClips ();
}
//---------------------------------根据名字找音源片段----------------------------
///
/// 更具名字找到SingleClip
///
/// 音效名字
/// 返回SingleClip
public SingleClip FindClipByName (string _clipName) {
for (int i = 0; i < m_clipName.Length; i++) {
if (m_clipName[i].Equals (_clipName)) //判断两个名字是否相等
return m_allSingleClip[i];
}
return null;
}
//=============================================================================
//---------------------------------加载音效到内存---------------------------------
///
/// 加载音效片段
///
public void LoadClips () {
m_allSingleClip = new SingleClip[m_clipName.Length];
//将Resources里的音效加载出来,并用一个类数组存起来
for (int i = 0; i < m_clipName.Length; i++) {
var tempClip = Resources.Load<AudioClip> ("AudioAssets/" + m_clipName[i]);
SingleClip tempSingle = new SingleClip (tempClip);
m_allSingleClip[i] = tempSingle;
}
}
//=============================================================================
//----------------------------------配置文件读取---------------------------------
//这里读取的是本地 一般情况是从服务器读取
///
/// 从配置文件读取
///
public void ReadConfig () {
//加载地址
string fileAddress = System.IO.Path.Combine (Application.streamingAssetsPath, "AudioConfig");
//打开文件
FileInfo fileInfo = new FileInfo (fileAddress);
//如果文件存在
if (fileInfo.Exists) {
//用文件系统来读取
StreamReader r = new StreamReader (fileAddress);
var tempStr = r.ReadLine ();
//从配置文件第一行读取总数
int lineCount = 0;
if (int.TryParse (tempStr, out lineCount)) {
m_clipName = new string[lineCount];
for (int i = 0; i < lineCount; i++) {
tempStr = r.ReadLine ();
//以 “空格” 分割 存在splits里
string[] splits = tempStr.Split (" ".ToCharArray ());
m_clipName[i] = splits[0];
}
r.Close ();
}
}
}
//=============================================================================
}
SingleClip类 这里为了区分单独写出来了 也可以直接写在ClipManager里面
/**
此类用来存clip片段 和 播放对应片段
**/
using UnityEngine;
public class SingleClip {
AudioClip clip;
public SingleClip (AudioClip _clip) {
this.clip = _clip;
}
///
/// 播放一个音效片段
///
/// 播放器
public void Play (AudioSource _audioSource) {
_audioSource.clip = clip;
_audioSource.Play ();
}
}
最后AudioManager 把左右管理者结合
using UnityEngine;
public class AudioManager : MonoBehaviour {
public static AudioManager Instance;
SourceManager m_sourceManager;
ClipManager m_clipManager;
private void Start () {
Instance = this;
m_sourceManager = new SourceManager (gameObject);
m_clipManager = new ClipManager ();
}
public void Play (string _audioName) {
//找空闲播放器
var tempSorce = m_sourceManager.GetFreeAudio ();
//找对应片段 返回SingleClip
var tempClip = m_clipManager.FindClipByName (_audioName);
tempClip.Play (tempSorce);
m_sourceManager.ReleaseFreeAudio ();
}
public void Stop (string _audioName) {
m_sourceManager.Stop (_audioName);
}
public void Free (){
m_sourceManager.ReleaseFreeAudio ();
}
}
只读
,区别在于:
这里用
Find
和匿名函数
只是为了方便演示 实际运用可以根据情况而定
释放的时机更具情况而定,可以达到某个条件释放,也可以做定时器释放
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour {
void Start () {
GameObject.Find ("Button1").GetComponent<Button> ().onClick.AddListener (() => {
AudioManager.Instance.Play ("asd");//使用方法
});
GameObject.Find ("Button2").GetComponent<Button> ().onClick.AddListener (() => {
AudioManager.Instance.Play ("qwe");
});
}
float t, freeTime = 5f;
void Update () {
t += Time.deltaTime;
if (t > freeTime) {
AudioManager.Instance.Free ();//释放方法
t = 0;
print ("释放");
}
}
}
学习笔记,仅供参考,如有不正,欢迎指正