UFL6-3——音效管理模块优化
优化频繁创建删除音效组件
目前我们音效管理器中的音效组件会频繁的创建和删除
这样会产生大量的内存垃圾,并且频繁创建对象也会带来性能消耗
因此我们可以利用缓存池对其进行优化
按照之前实现的缓存池要求,在场景上创建一个挂载音效源的对象,然后挂载一个poolObj
脚本,然后设置最大存在数量maxNum
因此,我们不再需要一个专门挂载音效源的对象,而是转为使用缓存池创建挂载音效源的对象
播放音效时,从缓存池内取出音效对象,停止播放音效(因为该音效可能正在播放其他音效),设置音效切片
停止播放或者帧更新检测播放停止时,清空关联的音效切片,从管理列表内移除,将音效对象压回对象池内,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| private List<AudioSource> soundList = new List<AudioSource>();
private MusicManager() { MonoManager.Instance.AddFixedUpdateListener(Update); }
private void Update() { if (!soundIsPlay) return; for (int i = soundList.Count - 1; i >= 0; i--) { if (!soundList[i].isPlaying) { soundList[i].clip = null; PoolManager.Instance.PushObj(soundList[i].gameObject); soundList.RemoveAt(i); } } }
public void PlaySound(string name, bool isLoop = false, bool isSync = false, UnityAction<AudioSource> callBack = null) { ABResManager.Instance.LoadResAsync<AudioClip>("sound", name, (clip) => { AudioSource source = PoolManager.Instance.GetObj("Sound/soundObj").GetComponent<AudioSource>(); source.Stop(); source.clip = clip; source.loop = isLoop; source.volume = soundVolume; source.Play(); if (!soundList.Contains(source)) soundList.Add(source); callBack?.Invoke(source); }, isSync); }
public void StopSound(AudioSource source) { if (soundList.Contains(source)) { source.Stop(); soundList.Remove(source); source.clip = null; PoolManager.Instance.PushObj(source.gameObject); } }
|
优化3D音效问题
由于我们使用了缓存池,因此AudioSource
依附的将会是一个个独立的游戏对象,而3D音效主要考虑的问题是:
- 音效依附在对象上跟随对象移动
- 音效中3D相关参数的设置
如果你想要使用3D音效,那么只需要获取到音效组件和它依附的对象就可以迎刃而解了
- 获取音效组件依附的对象,改变它的父对象,设置它的位置,音效便可以跟随对象移动
- 获取音效组件改变其中的3D音效相关参数即可完成相关设置
1 2 3 4 5 6 7 8 9 10 11
| if (GUILayout.Button("播放音效")) { MusicManager.Instance.PlaySound("sound_1", false, false, (source) => { GameObject soundObj = source.gameObject; source.gameObject.transform.SetParent(soundObj.transform); source.spatialBlend = 1f; }); }
|
提供清除所有音效的方法
目前过场景时,音效相关对象会被自动的删除,但是音效管理器中我们的容器还占着引用,我们应该提供方法清空容器
值得一提的是,该方法必须要在清空缓存池前去调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public void ClearSound() { for (int i = 0; i < soundList.Count; i++) { soundList[i].Stop(); soundList[i].clip = null; PoolManager.Instance.PushObj(soundList[i].gameObject); } soundList.Clear(); }
|
具体代码