Godot 音频 (4.x)
播放 SFX 和音乐,将它们通过总线路由,以分贝控制音量,并将游戏玩法与节拍同步。目标为 Godot 4.7。
何时使用
- 在播放音效或音乐、将音频路由到总线(Master/Music/SFX)、通过代码调整音量/静音、添加总线效果(混响、压缩器)、定位 3D 音频,或将事件同步到音乐时使用。
**何时*不*使用:** 与引擎无关的音频*设计*(自适应音乐结构、混音理念、闪避模式)→ audio-design;在 Godot 之外导入/编码资产。
核心工作流
- 选择播放器节点:
AudioStreamPlayer— 非定位(音乐、UI、全局 SFX)。AudioStreamPlayer2D/AudioStreamPlayer3D— 定位;音量和声像由距离决定。
- 将
AudioStream分配给stream(音乐/循环使用.ogg,短音效使用.wav),然后调用play()。对于随场景开始播放的音乐,设置autoplay。 - 路由到总线。 将播放器的
bus设置为命名总线(例如"Music"、"SFX")。在音频面板(底部停靠栏)中定义总线;每条总线都可以具有音量、静音、独奏和效果。 - 以 dB 控制音量,而不是线性(音频是对数)。
0 dB= 不变,-80 dB≈ 静音。使用linear_to_db/db_to_linear转换。 - 通过代码驱动音量/静音,使用
AudioServer按总线索引。 - 对于节奏,使用输出延迟补偿计算精确播放时间。
模式
1. 一次性 SFX(发射后不管)
@onready var sfx: AudioStreamPlayer = $Sfx # stream assigned in the editor
func play_jump() -> void:
sfx.pitch_scale = randf_range(0.95, 1.05) # slight variation avoids fatigue
sfx.play()
# For many overlapping copies, use an AudioStreamPlayer with an
# AudioStreamPolyphonic stream, or spawn short-lived players and free on `finished`.
2. 通过 AudioServer 设置总线音量和静音
func set_music_volume(linear_0_to_1: float) -> void:
var bus := AudioServer.get_bus_index("Music")
# Convert a 0..1 slider to decibels; clamp avoids -inf at 0.
AudioServer.set_bus_volume_db(bus, linear_to_db(maxf(linear_0_to_1, 0.0001)))
func toggle_sfx(muted: bool) -> void:
AudioServer.set_bus_mute(AudioServer.get_bus_index("SFX"), muted)
3. 在两条音乐轨道之间交叉淡入淡出
@onready var a: AudioStreamPlayer = $MusicA
@onready var b: AudioStreamPlayer = $MusicB
func crossfade_to(stream: AudioStream, secs := 1.5) -> void:
b.stream = stream
b.volume_db = -40.0
b.play()
var tw := create_tween().set_parallel(true)
tw.tween_property(a, "volume_db", -40.0, secs) # fade out current
tw.tween_property(b, "volume_db", 0.0, secs) # fade in next
tw.chain().tween_callback(a.stop)
var tmp := a; a = b; b = tmp # swap roles
4. 精确节拍计时(补偿输出延迟)
@onready var music: AudioStreamPlayer = $Music
func get_playback_time() -> float:
# Add time since the last audio mix, subtract output latency, for sub-frame accuracy.
var t := music.get_playback_position() + AudioServer.get_time_since_last_mix()
return t - AudioServer.get_output_latency()
常见陷阱
- 将音量视为线性。
volume_db/set_bus_volume_db是分贝。设置volume_db = 0.5接近满音量,而不是一半。使用linear_to_db映射滑块。 linear_to_db(0.0)是-inf。 转换前将线性值限制到一个很小最小值(例如0.0001),或特殊处理 0 → 静音。- 总线名称拼写错误会静默失败。
get_bus_index("Muisc")返回-1;后续调用会错误或无操作。匹配音频面板中的确切总线名称。 - 短音效会被截断,当同一播放器被重新触发时。使用单独播放器、
AudioStreamPolyphonic,或每次触发创建AudioStreamPlayer并在finished时释放。 - 音乐不会循环,除非导入/流循环已启用(
.ogg导入有 Loop 选项;AudioStreamWAV有loop_mode)。 - 仅使用
get_playback_position()同步会抖动 — 它按音频混合更新,而不是按帧更新;添加get_time_since_last_mix()并减去get_output_latency()。 - 3D 音频听不见 → 没有
AudioListener3D/Camera3D来听到它,或max_distance/衰减太紧,或错误总线被静音。
参考
- 有关总线布局(
.tres)、添加效果(混响/压缩器/EQ)和侧链闪避、AudioStreamPolyphonic/AudioStreamInteractive、麦克风捕获,以及使用AudioStreamGenerator的程序化音频,请阅读references/buses-and-effects.md。
相关技能
audio-design— 与引擎无关的自适应音乐、混音和闪避实践。godot-animation— 将动画/Tween 同步到get_playback_position()。godot-ui-control— 将音量滑块连接到AudioServer。