1、目标
实现游戏过程中的背景音乐。
2、Audio Mixer概念
(1)概念说明
Audio Mixer是一种强大的音频管理工具,用于组织、控制和处理游戏中的所有音频源。
它允许你创建音频层次结构、应用效果、调整音量,并在不同场景或游戏状态之间平滑切换。
有多个混音组(Groups)和效果器(Effects)组成,每个混音组可以有自己的音量、效果和子组,形成一个树形结构。主混音器组(Master)位于顶层,所有音频最终都通过它输出。
主要功能包括:
- 音量控制:独立调节不同类型音频的音量(如音乐、音效、对话)
- 音频效果:应用压缩器、混响、均衡器等效果
- 快照(Snapshots):保存和切换不同的音频设置(如从主菜单到游戏场景的过渡)
- 实时调整:在游戏运行时动态修改音频参数
快照允许你将一组混音器参数(如音量、效果器强度、发送级别等)保存为预设,并在游戏运行时通过代码或事件平滑地在不同预设之间过渡。
(2)项目配置
开启Audio Mixer:Window -> Audio -> Audio Mixer
在Assets -> Sounds下有音频文件:
点击Game Audio Mixer可以看到详细信息
点击Assets/Prefabs/Sound/Sound.prefab,配置Audio Source的Output信息:
后续所有的动作声音都会通过这个播放音频混音器进行调整。
3、编写代码
(1)创建SceneSoundsItem.cs脚本
在Assets/Scripts/Sounds下创建新脚本SceneSoundsItem.cs。
[System.Serializable]
public class SceneSoundsItem
{
public SceneName sceneName;
public SoundName ambientSoundForScene;
public SoundName musicForScene;
}
(2)创建SO_SceneSoundsList.cs脚本
在Assets/Scripts/Sounds下创建新脚本SO_SceneSoundsList.cs。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName ="so_SceneSoundsList", menuName ="Scriptable Objects/Sounds/Scene Sounds List")]
public class SO_SceneSoundsList : ScriptableObject
{
[SerializeField]
public List<SceneSoundsItem> sceneSoundsDetails;
}
(3)修改AudioManager.cs脚本
添加3个引入:
using System;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;
添加如下属性信息:
Awake函数添加代码:
添加如下函数:
private void OnEnable()
{
EventHandler.AfterSceneLoadEvent += PlaySceneSounds;
}
private void OnDisable()
{
EventHandler.AfterSceneLoadEvent -= PlaySceneSounds;
}
private void PlaySceneSounds()
{
SoundItem musicSoundItem = null;
SoundItem ambientSoundItem = null;
float musicPlayTime = defaultSceneMusicPlayTimeSeconds;
// Try Get current scene
if(Enum.TryParse<SceneName>(SceneManager.GetActiveScene().name, true, out SceneName currentSceneName))
{
// Get Music and Ambient Sounds for Scene
if(sceneSoundsDictionary.TryGetValue(currentSceneName, out SceneSoundsItem sceneSoundsItem))
{
soundDictionary.TryGetValue(sceneSoundsItem.musicForScene, out musicSoundItem);
soundDictionary.TryGetValue(sceneSoundsItem.ambientSoundForScene, out ambientSoundItem);
}
else
{
return;
}
// Stop any scene sounds already playing
if(playSceneSoundsCoroutine != null)
{
StopCoroutine(playSceneSoundsCoroutine);
}
// Play scene ambient sounds and music
playSceneSoundsCoroutine = StartCoroutine(PlaySceneSoundsRoutine(musicPlayTime, musicSoundItem, ambientSoundItem));
}
}
private IEnumerator PlaySceneSoundsRoutine(float musicPlaySeconds, SoundItem musicSoundItem, SoundItem ambientSoundItem)
{
if(musicSoundItem != null && ambientSoundItem != null)
{
// Start with ambient sound
PlayAmbientSoundClip(ambientSoundItem, 0f);
// Wait for random range of seconds before playing music
yield return new WaitForSeconds(UnityEngine.Random.Range(sceneMusicStartMinSecs, sceneMusicStartMaxSecs));
// Play music
PlayMusicSoundClip(musicSoundItem, musicTransitionSecs);
// Wait for music play seconds before transitioning to ambient sounds
yield return new WaitForSeconds(musicPlaySeconds);
// Play ambient sound clip
PlayAmbientSoundClip(ambientSoundItem, musicTransitionSecs);
}
}
private void PlayAmbientSoundClip(SoundItem ambientSoundItem, float transitionTimeSeconds)
{
// Set Volume
gameAudioMixer.SetFloat("AmbientVolume", ConvertSoundVolumeDecimalFractionToDecibels(ambientSoundItem.soundVolume));
// Set clip & play
ambientSoundAudioSource.clip = ambientSoundItem.soundClip;
ambientSoundAudioSource.Play();
// Transition to ambient
gameMusicSnapshot.TransitionTo(transitionTimeSeconds);
}
/// <summary>
/// Convert volumeDecimalFraction to -80 to +20 decibel range
/// </summary>
/// <param name="volumeDecimalFraction"></param>
/// <returns></returns>
private float ConvertSoundVolumeDecimalFractionToDecibels(float volumeDecimalFraction)
{
// Convert volume from deicimal fraction to -80 to +20 decibel range
return (volumeDecimalFraction * 100f - 80f);
}
private void PlayMusicSoundClip(SoundItem musicSoundItem, float transitionTimeSeconds)
{
// Set Volume
gameAudioMixer.SetFloat("MusicVolume", ConvertSoundVolumeDecimalFractionToDecibels(musicSoundItem.soundVolume));
// Set clip & play
ambientSoundAudioSource.clip = musicSoundItem.soundClip;
ambientSoundAudioSource.Play();
// Transition to ambient
gameAmbientSnapshot.TransitionTo(transitionTimeSeconds);
}
PlayAmbientSoundClip函数中的参数:
ConvertSoundVolumeDecimalFractionToDecibels函数:把小数转化为分贝。
gameAmbientSnapshot.TransitionTo(transitionTimeSeconds);使用 gameAmbientSnapshot
的 TransitionTo
方法,在指定的时间内平滑地过渡到环境音效的音频快照状态。这个过程通常用于在不同音频场景之间进行平滑的音量变化和效果切换。
4、创建SO对象
在Assets/Scriptable Object Assets/Sounds下创建so_SceneSoundsList.asset
填充数据如下:
5、配置AudioManager对象
在Hierarchy -> PersistentScene -> AudioManager下创建新物体命名为AmbientSound、GameMusic,配置如下:
配置其他参数如下:
调节Audio Mixer -> Snapshots -> MusicOnly,,AmbientMaster调到-10。
indoors1的音量调到0.75。
6、游戏测试
进入不同的Scene,会听到不同的背景音乐