关于 unity-audio
面向 Unity 开发者的音频系统参考技能,涵盖音源、监听器、混音器与空间音频的配置和脚本模式。也汇总音频导入、播放与资源管理中的常见问题。
主要功能
- 01介绍 AudioSource 与 AudioListener
- 02配置 Audio Mixer、效果与快照
- 03设置 3D 空间音频与衰减
- 04说明音频格式、加载和压缩设置
- 05提供音效播放、淡入淡出与音频池模式
- 06列出常见音频反模式
适用场景
- 01设置游戏对象的 3D 声音
- 02管理音乐、音效的混音与音量
- 03为长音频选择加载和压缩方式
- 04避免重叠播放或资源占用问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-audio安装后在 Claude Code 中输入/unity-audio确认已加载。
附带文件references/audio-api.md
详细介绍
Unity Audio System
音频系统概览
Unity 的音频系统提供完整的 3D 空间音效、实时混音和母带处理、混音器层级、快照以及预定义效果。其核心架构采用声源—监听器模型:
- AudioClip -- 导入项目的音频数据容器
- AudioSource -- 附加到 GameObject、用于播放 AudioClip 的组件
- AudioListener -- 类似麦克风的组件(通常位于 Main Camera 上),用于接收声源的音频并输出到扬声器
- Audio Mixer -- 用于混合声源、应用效果和处理母带输出的中央枢纽
声音由附加到对象上的 AudioSource 发出,并由 AudioListener 接收。Unity 会计算声源与监听器之间的距离和位置,以确定音量、声像和 3D 效果。系统还会根据声源对象与监听器对象的相对速度模拟多普勒效应。
支持的音频格式
| 格式 | 类型 |
|---|---|
.aif、.wav | 未压缩 |
.mp3、.ogg | 已压缩 |
.xm、.mod、.it、.s3m | 跟踪器模块 |
Unity 支持单声道、立体声和多声道音频资源(最多八个声道)。
AudioSource 和 AudioListener
AudioSource
AudioSource 组件可在场景中播放 AudioClip,并提供用于自定义播放行为的选项。主要属性:
| 属性 | 说明 | 默认值 |
|---|---|---|
clip | 要播放的 AudioClip | 无 |
volume | 播放音量(0.0 到 1.0) | 1.0 |
pitch | 播放速度/音高倍率 | 1.0 |
loop | 播放完毕后是否循环播放片段 | false |
playOnAwake | GameObject 激活时自动播放 | true |
spatialBlend | 2D(0.0)到 3D(1.0)的混合比例 | 0.0 |
priority | 声源优先级(0 = 最高,256 = 最低) | 128 |
mute | 静音声源但不停止播放 | false |
outputAudioMixerGroup | 用于路由的目标混音器组 | 无 |
3D 音效设置
| 属性 | 说明 |
|---|---|
dopplerLevel | 多普勒效应强度比例 |
spread | 3D 立体声/多声道的扩散角度(度) |
rolloffMode | 音量随距离衰减的方式(对数、线性、自定义) |
minDistance | 音量保持最大值的距离范围 |
maxDistance | 超出此距离后声音将不可听,或不再衰减 |
panStereo | 立体声声像位置(-1 为左声道,1 为右声道) |
reverbZoneMix | 混入全局混响的电平 |
AudioListener
AudioListener 是类似麦克风的设备,用于接收场景中 AudioSource 的输入,并通过扬声器输出。重要规则:
- 每个场景只能有一个 AudioListener -- 这是硬性限制
- 默认添加到 Main Camera
- 没有可配置的 Inspector 属性 -- 只需添加即可工作
- 处理 3D 定位音频和 2D 音频(后者不使用 3D 处理)
- 对所有可听见的声音应用 Reverb Zones 和 Audio Effects
可通过脚本访问的静态属性:
AudioListener.volume-- 主音量(0.0 到 1.0)AudioListener.pause-- 暂停/恢复整个音频系统
AudioClip 和导入设置
加载类型
| 加载类型 | 行为 | 适用场景 |
|---|---|---|
| 加载时解压 | 加载时立即解压;Vorbis 格式约占用 10 倍内存,ADPCM 格式约占用 3.5 倍内存 | 较小且频繁使用的音效 |
| 在内存中压缩 | 在内存中保持压缩状态,播放时解压;会略微增加 CPU 开销 | 中等大小的音频,且加载时解压会超出内存预算 |
| 流式传输 | 从磁盘即时解码;每个片段使用约 200KB 缓冲区 | 音乐或环境音轨等较长音频 |
压缩格式
| 格式 | 比率 | 最适用于 |
|---|---|---|
| PCM | 1:1(未压缩) | 无需消耗 CPU 解码的极短音效 |
| ADPCM | 3.5:1 | 噪声较大的声音(脚步声、撞击声、武器声) |
| Vorbis/MP3 | 可变(质量滑块) | 音乐和中等长度的音效 |
导入设置
| 设置 | 描述 |
|---|---|
| Force To Mono | 在打包前将多声道音频混合为单声道音轨 |
| Normalize | 在转换为单声道时对音频进行归一化 |
| Load In Background | 异步加载音频片段,以避免阻塞主线程 |
| Ambisonic | 标记文件包含 Ambisonic 编码的声场(用于 XR/360) |
| Preload Audio Data | 在场景加载完成时预加载音频片段数据(默认:启用) |
| Quality | Vorbis/MP3 格式的压缩质量滑块 |
| Sample Rate Setting | 保留、优化(自动调整)或覆盖(手动降低) |
音频混音器
音频混音器为音频输出提供混音、效果处理和母带处理功能。每个音频混音器资源默认都包含一个 Master Group。
核心概念
- Groups(总线) -- 控制音量衰减和音高校正的信号链;按层级组织(例如
Master/SFX/Weapons) - Snapshots(快照) -- 保存的参数配置,可在运行时在不同配置间切换,以营造不同的情绪或氛围
- Effects(效果) -- 应用于组信号链中的 DSP 效果(混响、回声、均衡器等)
- Send/Return(发送/返回) -- 将一个总线的结果传递到另一个总线,以便共享效果处理
- Ducking(闪避) -- 根据另一组的活动情况调整一组的输出(例如,播放对话时降低环境音量)
- Views(视图) -- 用于管理复杂混音器布局的不同可见性配置
- Exposed Parameters(公开参数) -- 通过
SetFloat/GetFloat提供脚本控制的混音器参数
注意: Web 平台仅部分支持音频混音器。
混音器脚本编写
using UnityEngine;
using UnityEngine.Audio;
public class MixerController : MonoBehaviour
{
[SerializeField] private AudioMixer mixer;
// Set exposed parameter (must be exposed in the Mixer Inspector)
public void SetVolume(float linear)
{
float dB = Mathf.Log10(Mathf.Max(linear, 0.0001f)) * 20f;
mixer.SetFloat("MasterVolume", dB);
}
// Read exposed parameter (convert dB back to linear)
public float GetVolume()
{
if (mixer.GetFloat("MasterVolume", out float dB))
return Mathf.Pow(10f, dB / 20f);
return 1f;
}
// Reset parameter to snapshot-defined value
public void ResetVolume() => mixer.ClearFloat("MasterVolume");
// Transition to a named snapshot
public void GoToSnapshot(string name, float time)
{
var snap = mixer.FindSnapshot(name);
if (snap != null) snap.TransitionTo(time);
}
// Blend multiple snapshots with weights
public void BlendSnapshots(AudioMixerSnapshot[] snaps, float[] weights, float time)
=> mixer.TransitionToSnapshots(snaps, weights, time);
}
3D 空间音频
基本 3D 声音设置
将 spatialBlend 设为 1.0,以实现完整的 3D 定位。Unity 内置的声像控制会根据听众的距离和角度调节左右耳的声音贡献。
空间化插件(HRTF)
对于高级 3D 音频,Unity 支持采用 HRTF 滤波的空间化插件。设置步骤:(1) Edit > Project Settings > Audio -- 选择空间化插件;(2) 在每个 AudioSource 上启用 Spatialize;(3) 可选地设置 spatializePostEffects。性能提示:仅对附近的声音进行空间化;远处的声音使用传统声像控制。
衰减模式
- Logarithmic -- 逼真:近处声音响亮,音量快速衰减(默认)
- Linear -- 在 minDistance 和 maxDistance 之间保持恒定衰减
- Custom -- 用户定义的 AnimationCurve
using UnityEngine;
public class SpatialAudioSetup : MonoBehaviour
{
[SerializeField] private AudioSource audioSource;
void Start()
{
// Configure for 3D spatial audio
audioSource.spatialBlend = 1.0f; // Full 3D
audioSource.rolloffMode = AudioRolloffMode.Logarithmic;
audioSource.minDistance = 1f;
audioSource.maxDistance = 50f;
audioSource.dopplerLevel = 1.0f;
audioSource.spread = 0f; // Point source
// Enable spatialization plugin (if configured in Project Settings)
audioSource.spatialize = true;
}
}
常见模式
播放音效
using UnityEngine;
public class SoundEffectPlayer : MonoBehaviour
{
[SerializeField] private AudioSource audioSource;
[SerializeField] private AudioClip shootClip;
[SerializeField] private AudioClip reloadClip;
// Play the assigned clip
public void PlayShoot()
{
audioSource.Play();
}
// PlayOneShot: plays a clip without interrupting the current one
// Supports overlapping sounds and per-call volume scaling
public void PlayReload(float volumeScale = 1.0f)
{
audioSource.PlayOneShot(reloadClip, volumeScale);
}
// Play a clip at a world position (creates a temporary AudioSource)
public void PlayExplosionAt(Vector3 position)
{
AudioSource.PlayClipAtPoint(shootClip, position, 1.0f);
}
// Play with a delay (in seconds)
public void PlayDelayed()
{
audioSource.PlayDelayed(0.5f);
}
// Scheduled playback on DSP timeline (sample-accurate)
public void PlayScheduled()
{
double startTime = AudioSettings.dspTime + 1.0;
audioSource.PlayScheduled(startTime);
}
}
音频对象池
using UnityEngine;
using System.Collections.Generic;
public class AudioPool : MonoBehaviour
{
[SerializeField] private int poolSize = 10;
private List<AudioSource> pool = new List<AudioSource>();
void Awake()
{
for (int i = 0; i < poolSize; i++)
{
var obj = new GameObject($"PooledAudio_{i}");
obj.transform.SetParent(transform);
var src = obj.AddComponent<AudioSource>();
src.playOnAwake = false;
pool.Add(src);
}
}
public AudioSource Play(AudioClip clip, Vector3 pos, float volume = 1f)
{
var source = pool.Find(s => !s.isPlaying);
if (source == null) return null;
source.transform.position = pos;
source.clip = clip;
source.volume = volume;
source.Play();
return source;
}
}
使用协程淡入淡出音频
using UnityEngine;
using System.Collections;
public class AudioFader : MonoBehaviour
{
[SerializeField] private AudioSource musicSource;
public void CrossFadeTo(AudioClip newClip, float duration)
{
StartCoroutine(CrossFadeCoroutine(newClip, duration));
}
private IEnumerator CrossFadeCoroutine(AudioClip newClip, float duration)
{
float startVol = musicSource.volume;
float half = duration / 2f;
// Fade out
for (float t = 0f; t < half; t += Time.deltaTime)
{ musicSource.volume = Mathf.Lerp(startVol, 0f, t / half); yield return null; }
// Switch clip and fade in
musicSource.clip = newClip;
musicSource.Play();
for (float t = 0f; t < half; t += Time.deltaTime)
{ musicSource.volume = Mathf.Lerp(0f, startVol, t / half); yield return null; }
musicSource.volume = startVol;
}
}
使用 UI 滑块控制混音器音量
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
public class VolumeSettings : MonoBehaviour
{
[SerializeField] private AudioMixer mixer;
[SerializeField] private Slider masterSlider;
void Start()
{
masterSlider.value = PlayerPrefs.GetFloat("MasterVol", 1f);
masterSlider.onValueChanged.AddListener(v => SetVolume("MasterVol", v));
}
// Exposed parameter names must match those set in the Audio Mixer Inspector
private void SetVolume(string param, float linear)
{
float dB = linear > 0.0001f ? Mathf.Log10(linear) * 20f : -80f;
mixer.SetFloat(param, dB);
PlayerPrefs.SetFloat(param, linear);
}
}
暂停和恢复音频
// Pause all audio globally
AudioListener.pause = true;
// UI sounds can bypass the global pause
uiSource.ignoreListenerPause = true;
// Resume all audio
AudioListener.pause = false;
// Pause/resume a single source (remembers playback position)
musicSource.Pause();
musicSource.UnPause();
反模式
1. 场景中存在多个 AudioListener
每个场景只能有一个 AudioListener。请从辅助摄像机中移除 AudioListener,或者在切换摄像机时将其禁用/启用。
2. 使用 Play() 播放重叠音效
// BAD: Play() restarts the clip, cutting off the previous playback
void OnShoot()
{
audioSource.clip = gunshot;
audioSource.Play(); // Interrupts previous gunshot
}
// GOOD: PlayOneShot allows overlapping instances
void OnShoot()
{
audioSource.PlayOneShot(gunshot, 0.8f);
}
3. 使用线性值设置混音器音量
// BAD: Mixer parameters use decibels, not linear 0-1
mixer.SetFloat("MasterVol", 0.5f); // Almost silent, not half volume
// GOOD: Convert linear to logarithmic decibels
float dB = Mathf.Log10(Mathf.Max(value, 0.0001f)) * 20f;
mixer.SetFloat("MasterVol", dB);
4. 将所有音频设置为 Decompress On Load 加载
将大型音频文件(音乐、对话)设置为 Decompress On Load 会占用大量内存(Vorbis 格式约为 10 倍)。长音频片段请使用 Streaming,中等长度的音频片段请使用 Compressed In Memory。
5. 忘记为 3D 声音设置 spatialBlend
// BAD: spatialBlend defaults to 0 (2D) -- sound ignores 3D position
AudioSource source = gameObject.AddComponent<AudioSource>();
source.clip = explosionClip;
source.Play(); // Plays at full volume regardless of distance
// GOOD: Set spatialBlend to 1 for 3D positioning
source.spatialBlend = 1.0f;
source.minDistance = 1f;
source.maxDistance = 50f;
source.Play();
6. 频繁播放音效时使用 PlayClipAtPoint
每次调用 PlayClipAtPoint 都会创建并销毁一个临时 GameObject。对于频繁播放的声音(枪声、脚步声),请改用音频对象池。
7. 3D 音效不要使用强制转为单声道
用作 3D 声源的立体声文件会浪费内存——在 3D 空间化过程中,立体声声道会合并为单声道。请在导入设置中为 3D 音效启用 Force To Mono。
关键 API 快速参考
| API | 说明 | 备注 |
|---|---|---|
AudioSource.Play() | 播放指定的片段 | 如果已在播放,则重新开始 |
AudioSource.PlayOneShot(clip, vol) | 播放片段,不会中断当前播放 | 支持重叠播放 |
AudioSource.PlayClipAtPoint(clip, pos) | 静态方法:在世界坐标位置播放 | 创建临时 GameObject |
AudioSource.PlayDelayed(delay) | 在延迟指定的秒数后播放 | |
AudioSource.PlayScheduled(time) | 在 DSP 时间播放 | 可实现采样级精度的调度 |
AudioSource.Stop() | 停止播放 | |
AudioSource.Pause() | 暂停播放 | 记住播放位置 |
AudioSource.UnPause() | 恢复已暂停的播放 | |
AudioSource.isPlaying | 声源当前是否正在播放 | 只读 |
AudioSource.time | 以秒为单位的播放位置 | 可读写 |
AudioSource.timeSamples | 以 PCM 采样为单位的播放位置 | 可读写 |
AudioListener.volume | 全局主音量 | 静态,0.0-1.0 |
AudioListener.pause | 暂停所有音频 | 静态 bool |
AudioClip.length | 片段时长(秒) | 只读 |
AudioClip.samples | 片段时长(采样数) | 只读 |
AudioClip.channels | 音频声道数 | 只读 |
AudioClip.frequency | 采样率(Hz) | 只读 |
AudioClip.loadState | 当前加载状态 | 只读 |
AudioClip.Create(name, len, ch, freq, stream) | 创建运行时 AudioClip | |
AudioClip.GetData(data, offset) | 将采样数据读入数组 | |
AudioClip.SetData(data, offset) | 将数组中的采样数据写入 | |
AudioClip.LoadAudioData() | 将片段数据加载到内存 | |
AudioClip.UnloadAudioData() | 从内存中卸载片段数据 | |
AudioMixer.SetFloat(name, val) | 设置公开参数 | 如果未找到,则返回 false |
AudioMixer.GetFloat(name, out val) | 获取公开参数值 | 如果未找到,则返回 false |
AudioMixer.ClearFloat(name) | 将参数重置为快照值 | |
AudioMixer.FindSnapshot(name) | 按精确名称查找快照 | 返回 AudioMixerSnapshot |
AudioMixer.FindMatchingGroups(path) | 按路径模式查找组 | 返回 AudioMixerGroup[] |
AudioMixer.TransitionToSnapshots(snaps, weights, time) | 按权重混合快照 | |
AudioMixerSnapshot.TransitionTo(time) | 过渡到此快照 |
相关技能
- unity-foundations -- GameObject、Component、Transform、Prefab、ScriptableObject
- unity-scripting -- C# 脚本模式、MonoBehaviour 生命周期、协程、事件
- unity-animation -- Animator Controller、Timeline、动画事件(适用于将音频与动画同步)