mcpField
U
unity-audio

unity-audio

github.com/nice-wolf-studio开发4069 次安装6 周前更新
代码仓库

关于 unity-audio

面向 Unity 开发者的音频系统参考技能,涵盖音源、监听器、混音器与空间音频的配置和脚本模式。也汇总音频导入、播放与资源管理中的常见问题。

主要功能

  1. 01介绍 AudioSource 与 AudioListener
  2. 02配置 Audio Mixer、效果与快照
  3. 03设置 3D 空间音频与衰减
  4. 04说明音频格式、加载和压缩设置
  5. 05提供音效播放、淡入淡出与音频池模式
  6. 06列出常见音频反模式

适用场景

  1. 01设置游戏对象的 3D 声音
  2. 02管理音乐、音效的混音与音量
  3. 03为长音频选择加载和压缩方式
  4. 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 空间音效、实时混音和母带处理、混音器层级、快照以及预定义效果。其核心架构采用声源—监听器模型:

  1. AudioClip -- 导入项目的音频数据容器
  2. AudioSource -- 附加到 GameObject、用于播放 AudioClip 的组件
  3. AudioListener -- 类似麦克风的组件(通常位于 Main Camera 上),用于接收声源的音频并输出到扬声器
  4. 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
playOnAwakeGameObject 激活时自动播放true
spatialBlend2D(0.0)到 3D(1.0)的混合比例0.0
priority声源优先级(0 = 最高,256 = 最低)128
mute静音声源但不停止播放false
outputAudioMixerGroup用于路由的目标混音器组无
3D 音效设置
属性说明
dopplerLevel多普勒效应强度比例
spread3D 立体声/多声道的扩散角度(度)
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 缓冲区音乐或环境音轨等较长音频
压缩格式
格式比率最适用于
PCM1:1(未压缩)无需消耗 CPU 解码的极短音效
ADPCM3.5:1噪声较大的声音(脚步声、撞击声、武器声)
Vorbis/MP3可变(质量滑块)音乐和中等长度的音效
导入设置
设置描述
Force To Mono在打包前将多声道音频混合为单声道音轨
Normalize在转换为单声道时对音频进行归一化
Load In Background异步加载音频片段,以避免阻塞主线程
Ambisonic标记文件包含 Ambisonic 编码的声场(用于 XR/360)
Preload Audio Data在场景加载完成时预加载音频片段数据(默认:启用)
QualityVorbis/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、动画事件(适用于将音频与动画同步)

其他资源

评论

支持 Markdown