强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Godot 4 GDScript 教程 / 音频系统

音频系统

概述

Godot 4 的音频系统提供了强大的音频播放、混音和效果处理能力。音频节点分为 2D/3D 空间音频和非空间音频(UI 音效、BGM),通过音频总线(Audio Bus)统一管理音量和效果。

节点说明适用场景
AudioStreamPlayer非空间音频BGM、UI 音效
AudioStreamPlayer2D2D 空间音频2D 游戏音效
AudioStreamPlayer3D3D 空间音频3D 游戏音效

AudioStreamPlayer(非空间音频)

基本用法

extends Node

@onready var bgm: AudioStreamPlayer = $BGMPlayer
@onready var sfx: AudioStreamPlayer = $SFXPlayer

func _ready():
    # 设置音量(分贝)
    bgm.volume_db = -6.0  # 负值降低音量
    # 设置音调
    bgm.pitch_scale = 1.0
    # 自动播放
    bgm.autoplay = true
    # 播放
    bgm.play()

func play_sfx(stream: AudioStream):
    sfx.stream = stream
    sfx.play()

# 多个音效同时播放
func play_sfx_concurrent(stream: AudioStream):
    var player = AudioStreamPlayer.new()
    player.stream = stream
    player.bus = "SFX"
    add_child(player)
    player.play()
    player.finished.connect(player.queue_free)

AudioStreamPlayer2D

extends Node2D

@onready var sfx: AudioStreamPlayer2D = $AudioStreamPlayer2D

func _ready():
    # 最大距离(像素)
    sfx.max_distance = 500.0
    # 衰减模型
    sfx.attenuation = 1.0  # 1.0 = 线性衰减
    # 衰减滤波
    sfx.attenuation_filter_cutoff_hz = 5000.0
    sfx.attenuation_filter_db = -24.0

func play_sound():
    sfx.play()

# 爆炸音效
func explosion_sound():
    sfx.max_distance = 1000.0
    sfx.volume_db = 3.0  # 爆炸声大一些
    sfx.play()

2D 音频属性

属性说明默认值
max_distance最大可听距离2000
attenuation衰减强度1.0
panning_strength左右声道分离强度1.0
bus音频总线名“Master”

AudioStreamPlayer3D

extends Node3D

@onready var sfx: AudioStreamPlayer3D = $AudioStreamPlayer3D

func _ready():
    # 最大距离(米)
    sfx.max_distance = 30.0
    # 衰减模型
    sfx.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_DISTANCE
    # 单位大小(距离参考值)
    sfx.unit_size = 10.0
    # 最大分贝
    sfx.max_db = 6.0
    # 多普勒效应
    sfx.doppler_tracking = AudioStreamPlayer3D.DOPPLER_TRACKING_PHYSICS_STEP

3D 衰减模型

模型公式适用场景
ATTENUATION_INVERSE_DISTANCE1/d通用
ATTENUATION_INVERSE_SQUARE_DISTANCE1/d²真实物理
ATTENUATION_LOGARITHMIClog(d)较大场景
ATTENUATION_DISABLED无衰减不推荐

聆听者设置

# 主摄像机应挂载 AudioListener3D
# Godot 4 中 Camera3D 内置监听功能
extends Camera3D

func _ready():
    # 3D 音频需要设置监听器
    # Camera3D 默认作为监听器
    make_current()  # 确保摄像机是当前活动摄像机

音频总线 Bus

音频总线是混音器通道,控制音量和效果链。

代码管理音频总线

extends Node

func _ready():
    # 创建新音频总线
    AudioServer.add_bus()
    var bus_idx = AudioServer.bus_count - 1
    AudioServer.set_bus_name(bus_idx, "SFX")
    AudioServer.set_bus_send(bus_idx, "Master")

    # 设置音量
    var master_idx = AudioServer.get_bus_index("Master")
    AudioServer.set_bus_volume_db(master_idx, -6.0)

    # 静音
    AudioServer.set_bus_mute(master_idx, false)

    # 声道平衡(-1 左,1 右)
    AudioServer.set_bus_send(master_idx, "Master")

常用音频总线结构

Master(主输出)
├── BGM(背景音乐)
├── SFX(音效)
│   ├── SFX_Weapons
│   └── SFX_UI
└── Voice(语音)

音频效果

添加回声效果

extends Node

func _ready():
    var bus_idx = AudioServer.get_bus_index("SFX")

    # 添加回声效果
    var echo = AudioEffectEcho.new()
    echo.delay_ms = 200.0
    echo.dry = 0.8       # 原始信号混合
    echo.wet = 0.3       # 效果信号混合
    echo.feedback = 0.4  # 反馈量
    echo.filter = 0.5    # 滤波
    AudioServer.add_bus_effect(bus_idx, echo)

添加混响效果

func add_reverb_to_bus(bus_name: String):
    var bus_idx = AudioServer.get_bus_index(bus_name)
    var reverb = AudioEffectReverb.new()
    reverb.room_size = 0.8     # 房间大小(0~1)
    reverb.damping = 0.5       # 阻尼
    reverb.wet = 0.2           # 湿信号
    reverb.dry = 0.8           # 干信号
    reverb.spread = 1.0        # 扩散
    reverb.hipass = 0.0        # 高通滤波
    AudioServer.add_bus_effect(bus_idx, reverb)

# 岩洞场景开启混响
func enter_cave():
    add_reverb_to_bus("SFX")

添加压缩器

func add_compressor(bus_name: String):
    var bus_idx = AudioServer.get_bus_index(bus_name)
    var comp = AudioEffectCompressor.new()
    comp.threshold = -20.0     # 触发阈值(分贝)
    comp.ratio = 4.0           # 压缩比
    comp.attack_us = 50.0      # 攻击时间(微秒)
    comp.release_ms = 200.0    # 释放时间(毫秒)
    comp.gain = 6.0            # 增益(分贝)
    AudioServer.add_bus_effect(bus_idx, comp)

添加 EQ 均衡器

func add_eq(bus_name: String):
    var bus_idx = AudioServer.get_bus_index(bus_name)
    var eq = AudioEffectEQ10.new()
    # 10 段 EQ,每段增益(分贝)
    eq.set_band_gain_db(0, -3.0)   # 32 Hz
    eq.set_band_gain_db(1, 0.0)    # 64 Hz
    eq.set_band_gain_db(2, 2.0)    # 125 Hz
    eq.set_band_gain_db(3, 3.0)    # 250 Hz
    eq.set_band_gain_db(4, 1.0)    # 500 Hz
    eq.set_band_gain_db(5, 0.0)    # 1k Hz
    eq.set_band_gain_db(6, -1.0)   # 2k Hz
    eq.set_band_gain_db(7, -2.0)   # 4k Hz
    eq.set_band_gain_db(8, -3.0)   # 8k Hz
    eq.set_band_gain_db(9, -4.0)   # 16k Hz
    AudioServer.add_bus_effect(bus_idx, eq)

音频效果速查表

效果类名用途
回声AudioEffectEcho延迟回声
混响AudioEffectReverb空间感
压缩AudioEffectCompressor动态范围控制
限制器AudioEffectLimiter防止爆音
EQ 10 段AudioEffectEQ10频率均衡
EQ 21 段AudioEffectEQ21精细均衡
低通滤波AudioEffectLowPassFilter柔化高频
高通滤波AudioEffectHighPassFilter去除低频
带通滤波AudioEffectBandPassFilter保留特定频段
失真AudioEffectDistortion过载效果
合唱AudioEffectChorus厚重感
音量切换AudioEffectAmplify增益调整

音量分贝控制

extends Node

# 线性音量(0.0~1.0)与分贝互转
func linear_to_db(linear: float) -> float:
    if linear <= 0:
        return -80.0  # 静音
    return 20.0 * log(linear) / log(10)

func db_to_linear(db: float) -> float:
    return pow(10.0, db / 20.0)

# 实际使用
func set_master_volume(linear: float):
    var master_idx = AudioServer.get_bus_index("Master")
    AudioServer.set_bus_volume_db(master_idx, linear_to_db(clamp(linear, 0.0, 1.0)))
线性值分贝值说明
1.00 dB原始音量
0.5-6 dB一半音量
0.25-12 dB四分之一
0.1-20 dB很小
0.0-∞静音

音频流类型

格式扩展名特点适用场景
WAV.wav无压缩,大文件短音效
OGG.ogg有损压缩,体积小BGM、长音频
MP3.mp3有损压缩,广泛兼容BGM(兼容性)

💡 提示:短音效(按键、脚步声)用 WAV,BGM 和长音频用 OGG 格式平衡质量与体积。


动态音乐系统

extends Node

@onready var layer_calm: AudioStreamPlayer = $CalmLayer
@onready var layer_combat: AudioStreamPlayer = $CombatLayer
@onready var layer_boss: AudioStreamPlayer = $BossLayer

var current_state: String = "calm"

func _ready():
    # 所有层同时播放,通过音量控制切换
    layer_calm.play()
    layer_combat.play()
    layer_boss.play()

    layer_calm.volume_db = 0
    layer_combat.volume_db = -80
    layer_boss.volume_db = -80

func transition_to(new_state: String, duration: float = 2.0):
    if new_state == current_state:
        return

    var tween = create_tween().set_parallel(true)

    # 淡出当前层
    match current_state:
        "calm":
            tween.tween_property(layer_calm, "volume_db", -80.0, duration)
        "combat":
            tween.tween_property(layer_combat, "volume_db", -80.0, duration)
        "boss":
            tween.tween_property(layer_boss, "volume_db", -80.0, duration)

    # 淡入新层
    match new_state:
        "calm":
            tween.tween_property(layer_calm, "volume_db", 0.0, duration)
        "combat":
            tween.tween_property(layer_combat, "volume_db", 0.0, duration)
        "boss":
            tween.tween_property(layer_boss, "volume_db", 0.0, duration)

    current_state = new_state

# 使用示例
func _on_combat_started():
    transition_to("combat")

func _on_boss_appeared():
    transition_to("boss")

func _on_combat_ended():
    transition_to("calm")

3D 空间音频实战

extends Node3D

# 环境音效系统
@onready var ambient_wind: AudioStreamPlayer3D = $AmbientWind
@onready var water_stream: AudioStreamPlayer3D = $WaterStream

func _ready():
    # 风声:全局环境
    ambient_wind.bus = "Ambient"
    ambient_wind.max_distance = 100.0
    ambient_wind.attenuation_model = AudioStreamPlayer3D.ATTENUATION_DISABLED

    # 水流声:位置感
    water_stream.bus = "SFX"
    water_stream.max_distance = 30.0
    water_stream.unit_size = 5.0

射击音效系统

extends Node3D

@export var shoot_sound: AudioStream
@export var impact_sound: AudioStream

func shoot():
    # 武器音效(3D 空间音效)
    var player = AudioStreamPlayer3D.new()
    player.stream = shoot_sound
    player.max_distance = 50.0
    player.unit_size = 3.0
    add_child(player)
    player.play()
    player.finished.connect(player.queue_free)

func play_impact(pos: Vector3):
    var player = AudioStreamPlayer3D.new()
    player.stream = impact_sound
    player.global_position = pos
    player.max_distance = 20.0
    get_tree().current_scene.add_child(player)
    player.play()
    player.finished.connect(player.queue_free)

音频与游戏事件联动

extends Node

@onready var ui_hover: AudioStreamPlayer = $UIHover
@onready var ui_click: AudioStreamPlayer = $UIClick
@onready var damage_sound: AudioStreamPlayer = $DamageSound
@onready var collect_sound: AudioStreamPlayer = $CollectSound

# UI 音效
func play_ui_hover():
    ui_hover.pitch_scale = randf_range(0.95, 1.05)  # 轻微随机化
    ui_hover.play()

func play_ui_click():
    ui_click.pitch_scale = randf_range(0.98, 1.02)
    ui_click.play()

# 游戏音效
func _on_player_damaged(amount: float):
    damage_sound.pitch_scale = randf_range(0.9, 1.1)
    damage_sound.volume_db = clampf(amount * 0.1, -12, 3)
    damage_sound.play()

func _on_item_collected():
    collect_sound.play()

# 脚步声随机化
func play_footstep(player: AudioStreamPlayer3D):
    player.pitch_scale = randf_range(0.85, 1.15)
    player.volume_db = randf_range(-3.0, 0.0)
    player.play()

音频最佳实践

实践说明
使用音频总线分组BGM / SFX / Voice 分开管理
短音效用 WAV避免解码开销
长音频用 OGG节省内存
随机化音调pitch_scalerandf_range 避免重复感
淡入淡出场景切换时平滑过渡
对象池复用频繁播放的音效复用 AudioStreamPlayer
合理设置 max_distance远处物体不消耗音频资源

游戏开发场景

场景推荐方案
BGMAudioStreamPlayer + 音频总线
2D 音效AudioStreamPlayer2D + 随机化
3D 环境音AudioStreamPlayer3D + Ambient 总线
动态音乐多层 AudioStreamPlayer + 淡入淡出
UI 音效AudioStreamPlayer + SFX 总线
语音对话AudioStreamPlayer + Voice 总线

⚠️ 常见陷阱

  1. 分贝不是线性的-6 dB 约等于一半音量,-20 dB 是原来的十分之一
  2. pitch_scale 改变音调也改变播放速度,Godot 4 无独立速度控制
  3. 同时播放太多音效会卡顿,使用对象池限制并发数
  4. OGG 文件在 Web 导出可能有兼容性问题,Web 平台优先使用 WAV/MP3
  5. AudioStreamPlayer3D 需要 Camera3D 作为监听器,否则无声

扩展阅读