需求
- 在大厅、游戏场景都可以打开设置面板,设置音乐、音效的音量;
- 整个游戏所有的声源都按玩家设置的音量播放。这需要所有声源1.初始化时设置为玩家设置音量,2.玩家改变设置时所有声源改变音量;
分析
管理器在各个场景都存在,可以:
- 不继承MonoBehavior,就不能和AudioSource挂在一个对象,也不能通过拖指定音乐和UI音效AudioSource。如果在场景里建好AudioSource,让它用GameObject.Find()或transform.Find()找AudioSource,那么每个场景都要创建,容易漏掉。所以这条路最好让管理器新建对象,添加AudioSource。
- 继承MonoBehavior,可以拖了,每个场景都建一个,同理容易漏建,不是好方案。
- 继承MonoBehavior,并且DontDestroyOnLoad。
总之,手动在每个场景创建管理器不是好方案,如果又想拖,那么继承MonoBehavior,DontDestroyOnLoad可能是最好的方案。
附加声源的组件
我们发现AudioSource不能继承,那么就弄一个附加在AudioSourced的组件,它只干2件事
- 初始时把自己依附的声源设置为用户设置的音量;
- 用户设置音量变化时更新自己声源的音量;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MyFarm
{
[RequireComponent(typeof(AudioSource))]
public class AudioController:MonoBehaviour
{
AudioSource _audioSource;
AudioSource audioSource
{
get
{
if(_audioSource == null)
{
_audioSource = GetComponent<AudioSource>();
}
return _audioSource;
}
}
private void Start()
{
UpdateVolume(MySettingsManager.Instance.settings.volume);
MySettingsManager.Instance.onVolumeChanged += UpdateVolume;
}
private void OnDestroy()
{
MySettingsManager.Instance.onVolumeChanged -= UpdateVolume;
}
void UpdateVolume(float volume)
{
audioSource.volume = volume;
}
}
}
这是一个观察者模式的典型应用场景,因为
- 管理器去找各个声源比较麻烦,但还能做到;
- 更麻烦的是声源是随时可能出现、销毁的,如果让管理器维护声源Collection,管理器无法知道什么时候有声源出现、销毁,但是声源知道自己何时出现、销毁,且访问管理器很容易;
音量管理器(或者设置管理器)
玩家在设置面板修改音量>音量管理器音量值变化>触发音量变化委托>所有监听者更新。
旧版设计
维护字典
管理器维护一个字典,键是int InatanceID。
管理器怎么分清哪个是音乐,哪些是音效?可以把音乐AudioSource和UI音效AudioSource单独拖。其他通过FindObjectsByType(),再和音乐、UI音效AudioSource对比判断是其他AudioSource。
但是转换场景时要重新获得一遍场景所有的AudioSource。管理器怎么知道什么时候切换场景了?
如果还有运行中创建AudioSource,声音管理器又怎么知道?创建AudioSource的脚本通知一下声音管理器?
走这条路,需要自己继承一个AudioSource,叫MyAudioSource,初始化时把自己加入管理器字典,销毁时移出字典。修改音量时遍历一遍字典。
或者修改音量也可以MyAudioSource监听管理器修改音量的事件。
然后发现AudioSource不允许继承。
那就还是通过各个引用AudioSource的脚本加入、移出字典。
只封装播放方法?
需要把项目所有的audioSource.Play()替换成自己封装的方法。先找到一个audioSource.Play(),再对Play()寻找引用,替换audioSource.Play()。
public void MyPlaySound(AudioSource audioSource){
audioSource.volume=DataManager.Instance.settingsData.soundVolume;
audioSource.Play();
}
音乐在游戏开始运行时开始播放,需要在初始化、玩家改变音量时设置音量。各AudioSource知道自己是音乐、UI音效还是其他音效,也知道自己什么时候播放,无需关心场景有没有切换。
问题是环境音效,比如鸟叫,是不用调用Play的,从一开始就播放并且循环播放,也要设置为玩家设置的音量,并且玩家修改设置时要改变音量。
总结
要么维护字典,要么监听事件,且由各个引用AudioSource的脚本负责添加、移除。为此可以定义一个接口,强制

2864

被折叠的 条评论
为什么被折叠?



