集成教程:
【游戏音效】Unity集成Wwise并进行开发的全流程教程(一)准备工作
【游戏音效】Unity集成Wwise并进行开发的全流程教程(二)Wwise项目
前言
这一篇章是Unity接入Wwise的代码。如果看了前面两章的介绍,那么就会比较清晰地明白脚本为什么要这么写。
提要
1.绑定Wwsie项目并配置对应的项目设置
2.脚本交互:初始化,播放,音量,停止,开关,清理
3.热更资源配置路径
绑定Wwsie项目
我们之前已经建好了一个项目,在导入Wwise时可以选择我们项目的位置。
如果没有现成的项目,这个地方可以不用管,Wwise会安装默认位置去创建一个。
导入之后,在Wwise Picker面板可以看到我们之前设置好的数据。
这里是一些项目配置。包括WwiseProject的路径,SoundBanks的设置路径。但是如果在Wwise项目导出SoundBank的选择种,选了对应的Overirde,这里就会不生效。
Create WwiseGlobal GameObejct,这个选项我是取消的。我的做法是自己生成进行控制。
常用功能
这里讲一下音效系统中最常用的几个功能。
初始化
初始化要做两件事:
1.确保有AkInitializer对象,并赋值上了AkWwiseInitializationSettings
2.得到Event和SoundBank的映射数据
【AkInitializer】
这个是可以在Wwise Setting面板选择自动生成的【Create WwiseGlobal GameObejct选项】。不过我的做法是自己控制创建。
AkWwiseInitializationSettings对象是我们之前设置的Generated的相关数据,实际对象是存储在Resources里面的AkWwiseInitializationSettings.Asset。这个是默认放置在Resources里,所以如果不改动的话不要打到ab包去了,免得打重。这个对象必须要有,因为在真机运行时,就是靠这个对象拿到设置的数据。
在创建时必须时先SetActive为false,因为AkWwiseInitializationSettings是在Awake时进行初始化的。挂载脚本的时候,AkWwiseInitializationSettings还未存在就会直接报错,即便是后面赋值也不行。
public void Init()
{
GameObject global = new GameObject(m_WwiseGlobalPrefabName);
global.SetActive(false);
GameObject.DontDestroyOnLoad(global);
AkInitializer akInitializer = global.AddComponent<AkInitializer>();
object settingObj = Resources.Load("AkWwiseInitializationSettings");
if (settingObj != null)
{
AkWwiseInitializationSettings settings = settingObj as AkWwiseInitializationSettings;
akInitializer.InitializationSettings = settings;
global.SetActive(true);
}
}
【Event和SoundBank的映射】
我的做法是解析SoundbankInfos.xml,里面有所有具体的信息。我的做法就是读取解析文本,大家可以根据情况选择自己的做法。而SoundbankInfos.xml是什么,具体可以看上一章,里面有详细的介绍。
最终是存储在一个字典里面,最终可以根据字典来得到映射关系。
脚本
播放 音量
public void PlaySound(string soundName)
{
if (string.IsNullOrEmpty(soundName))
{
return;
}
if (!m_PlaySound)
{
return;
}
PlayEvent("Play", soundName, null, m_SoundVolume, true);
}
private void PlayEvent(string handName, string eventName, GameObject gameObject, float volume, bool finishCallback = false)
{
if (listener == null)
{
return;
}
//EventName我使用默认的“操作_资源名”,如:Play_Close。用户输入直接输入Close即可。
string resourceName = handName + "_" + eventName;
string bankName;
//m_BankInfoDict是Event和SoundBank的映射关系字典
if (!m_BankInfoDict.TryGetValue(resourceName, out bankName))
{
Debug.LogError(string.Format("加载event({0})失败,没有找到所属的SoundBank", resourceName));
return;
}
if (!m_LoadBankList.Contains(bankName))
{
//加载SoundBank
AkBankManager.LoadBank(bankName, false, false);
m_LoadBankList.Add(bankName);
}
if (gameObject == null)
{
//加载一个预制体,预制体是空的
gameObject = AddSoundGameObject(eventName);
}
//播放
AkSoundEngine.PostEvent(resourceName, gameObject, (uint) m_CallbackType, finishCallback ? m_SoundFinishCallback : null, null);
//设置音量
AkSoundEngine.SetGameObjectOutputBusVolume(gameObject, listener, volume);
}
停止
//第一种方法
AkSoundEngine.StopAll(targetGameObject);
//第二种
AkSoundEngine.PostEvent("Stop_" + soundName,targetGameObject)
开关
开关我没有使用Wwise的接口,而是自己记录一下。开就播放,关就调整音量为0。我不停掉音效的原因是,将音量调整为0再调整音效为可听见状态,中间是很自然的过度。如果是停掉再开就会重新播放。当然这个要看个人选择。
清理
AkSoundEngine.ClearBanks();
热更
Wwise可以设置一个路径作为最优先的加载路径。这个路径是填什么就是什么,Wwise不会再加以修改。以下是我的设置。这个可以根据自己的需求来设置。在Windows的情况下不需要设置。
#if !UNITY_EDITOR
string newPath = Application.persistentDataPath + "/core/" + settings.UserSettings.m_BasePath;
#if UNITY_ANDROID
newPath += "Android";
#elif UNITY_IOS
newPath += "iOSResource";
#else
newPath += "Windows";
#endif
Debug.Log(string.Format("添加搜索路径:{0}",newPath));
AkSoundEngine.AddBasePath(newPath);
#endif