godot-audio-systems

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Audio Systems

音频系统

Expert guidance for Godot's audio engine and mixing architecture.
Godot音频引擎与混音架构的进阶指南。

NEVER Do

绝对不要做的事

  • NEVER create new AudioStreamPlayer nodes for every sound — Causes memory bloat and GC spikes. Use audio pooling (reuse players) or one-shot helper function.
  • NEVER set AudioServer bus volume with linear values
    set_bus_volume_db()
    expects decibels (-80 to 0). Use
    linear_to_db()
    for 0.0-1.0 conversion.
  • NEVER forget to set
    autoplay = false
    on music players
    — Music autoplays on scene load by default. Causes overlapping tracks when changing scenes.
  • NEVER use AudioStreamPlayer3D without attenuation model — Default attenuation is NONE (no falloff). Set
    attenuation_model
    to ATTENUATION_INVERSE_DISTANCE or audio is global.
  • NEVER play AudioStreamPlayer without checking
    playing
    first
    — Restarting an already-playing sound cuts it off. Check
    if not player.playing:
    before play().

  • 绝对不要为每个音效创建新的AudioStreamPlayer节点——这会导致内存膨胀和GC峰值。请使用音频池(复用播放器)或一次性辅助函数。
  • 绝对不要用线性值设置AudioServer总线音量——
    set_bus_volume_db()
    需要传入分贝值(范围-80到0)。使用
    linear_to_db()
    将0.0-1.0的线性值转换为分贝。
  • 绝对不要忘记给音乐播放器设置
    autoplay = false
    ——音乐播放器默认会在场景加载时自动播放,切换场景时会导致音轨重叠。
  • 绝对不要在未设置衰减模型的情况下使用AudioStreamPlayer3D——默认衰减模式为NONE(无衰减)。请将
    attenuation_model
    设置为ATTENUATION_INVERSE_DISTANCE,否则音频会全局播放。
  • 绝对不要在未检查
    playing
    状态的情况下播放AudioStreamPlayer
    ——重启正在播放的音效会打断它。播放前请检查
    if not player.playing:

Available Scripts

可用脚本

MANDATORY: Read the appropriate script before implementing the corresponding pattern.
强制要求:在实现对应方案前,请先阅读相应的脚本。

audio_manager.gd

audio_manager.gd

AudioManager singleton with sound pooling (32-player pool), bus assignment, and crossfade preparation. Prevents node spam and GC spikes.
AudioManager单例,包含音频池(32个播放器的池)、总线分配和淡入淡出准备功能。可避免节点泛滥和GC峰值。

audio_visualizer.gd

audio_visualizer.gd

Real-time FFT spectrum analysis. Captures low/mid/high frequency ranges to drive visual effects like lighting pulses or shader parameters.

实时FFT频谱分析工具。可捕获低/中/高频范围,驱动灯光闪烁或着色器参数等视觉效果。

AudioStreamPlayer Variants

AudioStreamPlayer变体

AudioStreamPlayer (Global/UI)

AudioStreamPlayer(全局/UI用)

gdscript
undefined
gdscript
undefined

No spatial positioning, same volume everywhere

无空间定位,所有位置音量一致

Use for: Music, UI sounds, voiceovers

适用场景:音乐、UI音效、旁白

@onready var music := AudioStreamPlayer.new()
func _ready() -> void: music.stream = load("res://audio/music_main.ogg") music.volume_db = -10 # Quieter music.autoplay = false music.bus = "Music" # Route to Music bus add_child(music) music.play()
undefined
@onready var music := AudioStreamPlayer.new()
func _ready() -> void: music.stream = load("res://audio/music_main.ogg") music.volume_db = -10 # 音量更低 music.autoplay = false music.bus = "Music" # 路由到Music总线 add_child(music) music.play()
undefined

AudioStreamPlayer2D (Positional)

AudioStreamPlayer2D(位置音频)

gdscript
undefined
gdscript
undefined

2D panning based on distance from camera

根据与相机的距离实现2D声像定位

Use for: 2D games, top-down audio cues

适用场景:2D游戏、俯视角音频提示

extends Area2D
@onready var footstep := AudioStreamPlayer2D.new()
func _ready() -> void: footstep.stream = load("res://audio/footstep.ogg") footstep.max_distance = 500 # Audible range (pixels) footstep.attenuation = 2.0 # Falloff curve (higher = faster fadeout) add_child(footstep)
func play_footstep() -> void: if not footstep.playing: footstep.play()
undefined
extends Area2D
@onready var footstep := AudioStreamPlayer2D.new()
func _ready() -> void: footstep.stream = load("res://audio/footstep.ogg") footstep.max_distance = 500 # 可听范围(像素) footstep.attenuation = 2.0 # 衰减曲线(值越高,淡出越快) add_child(footstep)
func play_footstep() -> void: if not footstep.playing: footstep.play()
undefined

AudioStreamPlayer3D (Spatial)

AudioStreamPlayer3D(空间音频)

gdscript
undefined
gdscript
undefined

3D spatial audio with doppler, reverb send

支持多普勒效应、混响发送的3D空间音频

Use for: 3D games, realistic sound positioning

适用场景:3D游戏、真实感音效定位

extends Node3D
@onready var explosion := AudioStreamPlayer3D.new()
func _ready() -> void: explosion.stream = load("res://audio/explosion.ogg") explosion.unit_size = 10.0 # Size of sound source explosion.max_distance = 100.0 # Range explosion.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_DISTANCE explosion.doppler_tracking = AudioStreamPlayer3D.DOPPLER_TRACKING_PHYSICS_STEP add_child(explosion)
explosion.play()

---
extends Node3D
@onready var explosion := AudioStreamPlayer3D.new()
func _ready() -> void: explosion.stream = load("res://audio/explosion.ogg") explosion.unit_size = 10.0 # 声源大小 explosion.max_distance = 100.0 # 可听范围 explosion.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_DISTANCE explosion.doppler_tracking = AudioStreamPlayer3D.DOPPLER_TRACKING_PHYSICS_STEP add_child(explosion)
explosion.play()

---

AudioBus Architecture

AudioBus架构

Bus Setup (Project Settings)

总线设置(项目设置)

Master (always exists)
  ├─ Music
  │   └─ Effects: Compressor, EQ
  ├─ SFX
  │   └─ Effects: Reverb (for environment)
  └─ Ambient
      └─ Effects: LowPassFilter (muffled ambience)
Master(默认存在)
  ├─ Music
  │   └─ 效果:压缩器、均衡器
  ├─ SFX
  │   └─ 效果:混响(用于环境音效)
  └─ Ambient
      └─ 效果:低通滤波器(营造闷响环境音)

Volume Control (Decibels)

音量控制(分贝)

gdscript
undefined
gdscript
undefined

❌ BAD: Linear volume (doesn't work)

❌ 错误:线性音量(无法正常工作)

AudioServer.set_bus_volume_db(music_bus_idx, 0.5) # WRONG!
AudioServer.set_bus_volume_db(music_bus_idx, 0.5) # 错误!

✅ GOOD: Use decibels

✅ 正确:使用分贝值

var music_bus := AudioServer.get_bus_index("Music") AudioServer.set_bus_volume_db(music_bus, -10) # -10 dB (quieter)
var music_bus := AudioServer.get_bus_index("Music") AudioServer.set_bus_volume_db(music_bus, -10) # -10分贝(音量更低)

Convert linear (0.0-1.0) to dB:

将线性值(0.0-1.0)转换为分贝:

var linear_volume := 0.5 # 50% var db := linear_to_db(linear_volume) # ~-6 dB AudioServer.set_bus_volume_db(music_bus, db)
var linear_volume := 0.5 # 50% var db := linear_to_db(linear_volume) # 约-6分贝 AudioServer.set_bus_volume_db(music_bus, db)

Convert dB to linear:

将分贝转换为线性值:

var current_db := AudioServer.get_bus_volume_db(music_bus) var linear := db_to_linear(current_db) print("Current volume: %d%%" % int(linear * 100))
undefined
var current_db := AudioServer.get_bus_volume_db(music_bus) var linear := db_to_linear(current_db) print("当前音量:%d%%" % int(linear * 100))
undefined

Mute Bus

静音总线

gdscript
func toggle_mute(bus_name: String) -> void:
    var bus_idx := AudioServer.get_bus_index(bus_name)
    var is_muted := AudioServer.is_bus_mute(bus_idx)
    AudioServer.set_bus_mute(bus_idx, not is_muted)

gdscript
func toggle_mute(bus_name: String) -> void:
    var bus_idx := AudioServer.get_bus_index(bus_name)
    var is_muted := AudioServer.is_bus_mute(bus_idx)
    AudioServer.set_bus_mute(bus_idx, not is_muted)

Audio Pooling (Performance)

音频池(性能优化)

Problem: Creating Players Every Frame

问题:每帧创建播放器

gdscript
undefined
gdscript
undefined

❌ BAD: Creates 60 new nodes/second at 60 FPS

❌ 错误:60 FPS下每秒创建60个新节点

func play_footstep() -> void: var player := AudioStreamPlayer.new() add_child(player) player.stream = load("res://audio/footstep.ogg") player.finished.connect(player.queue_free) player.play() # Result: 3600 nodes created in 1 minute!
undefined
func play_footstep() -> void: var player := AudioStreamPlayer.new() add_child(player) player.stream = load("res://audio/footstep.ogg") player.finished.connect(player.queue_free) player.play() # 结果:1分钟内创建3600个节点!
undefined

Solution: Audio Pool

解决方案:音频池

gdscript
undefined
gdscript
undefined

audio_pool.gd (AutoLoad)

audio_pool.gd(自动加载)

extends Node
const POOL_SIZE = 10 var pool: Array[AudioStreamPlayer] = [] var pool_index := 0
func _ready() -> void: # Pre-create players for i in range(POOL_SIZE): var player := AudioStreamPlayer.new() player.bus = "SFX" add_child(player) pool.append(player)
func play_sound(stream: AudioStream, volume_db := 0.0) -> void: var player := pool[pool_index] pool_index = (pool_index + 1) % POOL_SIZE # Round-robin
# Stop previous sound if still playing
if player.playing:
    player.stop()

player.stream = stream
player.volume_db = volume_db
player.play()
extends Node
const POOL_SIZE = 10 var pool: Array[AudioStreamPlayer] = [] var pool_index := 0
func _ready() -> void: # 预创建播放器 for i in range(POOL_SIZE): var player := AudioStreamPlayer.new() player.bus = "SFX" add_child(player) pool.append(player)
func play_sound(stream: AudioStream, volume_db := 0.0) -> void: var player := pool[pool_index] pool_index = (pool_index + 1) % POOL_SIZE # 循环复用
# 如果播放器正在播放,先停止
if player.playing:
    player.stop()

player.stream = stream
player.volume_db = volume_db
player.play()

Usage:

使用方式:

AudioPool.play_sound(load("res://audio/coin.ogg"), -5.0)

---
AudioPool.play_sound(load("res://audio/coin.ogg"), -5.0)

---

Music Transitions

音乐过渡

Crossfade Between Tracks

音轨间淡入淡出

gdscript
undefined
gdscript
undefined

music_manager.gd (AutoLoad)

music_manager.gd(自动加载)

extends Node
@onready var track_a := AudioStreamPlayer.new() @onready var track_b := AudioStreamPlayer.new()
var current_track: AudioStreamPlayer var fade_duration := 2.0
func _ready() -> void: track_a.bus = "Music" track_b.bus = "Music" add_child(track_a) add_child(track_b) current_track = track_a
func crossfade_to(new_stream: AudioStream) -> void: var next_track := track_b if current_track == track_a else track_a
# Start new track at 0 dB
next_track.stream = new_stream
next_track.volume_db = -80  # Silent
next_track.play()

# Fade out current, fade in next
var tween := create_tween().set_parallel(true)
tween.tween_property(current_track, "volume_db", -80, fade_duration)
tween.tween_property(next_track, "volume_db", 0, fade_duration)

await tween.finished

# Stop old track
current_track.stop()
current_track = next_track
undefined
extends Node
@onready var track_a := AudioStreamPlayer.new() @onready var track_b := AudioStreamPlayer.new()
var current_track: AudioStreamPlayer var fade_duration := 2.0
func _ready() -> void: track_a.bus = "Music" track_b.bus = "Music" add_child(track_a) add_child(track_b) current_track = track_a
func crossfade_to(new_stream: AudioStream) -> void: var next_track := track_b if current_track == track_a else track_a
# 新音轨以0分贝启动(初始静音)
next_track.stream = new_stream
next_track.volume_db = -80  # 静音
next_track.play()

# 当前音轨淡出,新音轨淡入
var tween := create_tween().set_parallel(true)
tween.tween_property(current_track, "volume_db", -80, fade_duration)
tween.tween_property(next_track, "volume_db", 0, fade_duration)

await tween.finished

# 停止旧音轨
current_track.stop()
current_track = next_track
undefined

BPM-Synced Transitions

BPM同步过渡

gdscript
undefined
gdscript
undefined

Transition on beat boundary

在节拍边界处切换

var bpm := 120.0 # Beats per minute var beat_duration := 60.0 / bpm # 0.5s per beat
func queue_transition_on_beat(new_stream: AudioStream) -> void: # Wait for next beat var current_time := current_track.get_playback_position() var time_to_next_beat := beat_duration - fmod(current_time, beat_duration)
await get_tree().create_timer(time_to_next_beat).timeout
crossfade_to(new_stream)

---
var bpm := 120.0 # 每分钟节拍数 var beat_duration := 60.0 / bpm # 每个节拍0.5秒
func queue_transition_on_beat(new_stream: AudioStream) -> void: # 等待下一个节拍 var current_time := current_track.get_playback_position() var time_to_next_beat := beat_duration - fmod(current_time, beat_duration)
await get_tree().create_timer(time_to_next_beat).timeout
crossfade_to(new_stream)

---

Dynamic Audio Effects

动态音频效果

Add Effect at Runtime

运行时添加效果

gdscript
undefined
gdscript
undefined

Add reverb to SFX bus

给SFX总线添加混响

var sfx_bus := AudioServer.get_bus_index("SFX") var reverb := AudioEffectReverb.new() reverb.room_size = 0.8 # Large room reverb.damping = 0.5 reverb.wet = 0.3 # 30% effect, 70% dry AudioServer.add_bus_effect(sfx_bus, reverb)
undefined
var sfx_bus := AudioServer.get_bus_index("SFX") var reverb := AudioEffectReverb.new() reverb.room_size = 0.8 # 大房间 reverb.damping = 0.5 reverb.wet = 0.3 # 30%效果,70%干声 AudioServer.add_bus_effect(sfx_bus, reverb)
undefined

Underwater Effect

水下音效

gdscript
func set_underwater(enabled: bool) -> void:
    var sfx_bus := AudioServer.get_bus_index("SFX")
    
    if enabled:
        # Add low-pass filter (muffled sound)
        var lowpass := AudioEffectLowPassFilter.new()
        lowpass.cutoff_hz = 500  # Cut frequencies above 500 Hz
        AudioServer.add_bus_effect(sfx_bus, lowpass)
    else:
        # Remove all effects
        for i in range(AudioServer.get_bus_effect_count(sfx_bus)):
            AudioServer.remove_bus_effect(sfx_bus, 0)

gdscript
func set_underwater(enabled: bool) -> void:
    var sfx_bus := AudioServer.get_bus_index("SFX")
    
    if enabled:
        # 添加低通滤波器(营造闷响)
        var lowpass := AudioEffectLowPassFilter.new()
        lowpass.cutoff_hz = 500  # 过滤500Hz以上的频率
        AudioServer.add_bus_effect(sfx_bus, lowpass)
    else:
        # 移除所有效果
        for i in range(AudioServer.get_bus_effect_count(sfx_bus)):
            AudioServer.remove_bus_effect(sfx_bus, 0)

Procedural Audio

程序化音频

Synthesize Beep

合成蜂鸣声

gdscript
undefined
gdscript
undefined

Generate simple sine wave

生成简单的正弦波

func create_beep(frequency: float, duration: float) -> AudioStreamGenerator: var stream := AudioStreamGenerator.new() stream.mix_rate = 44100 # Sample rate
var playback := stream.instantiate_playback()

var increment := frequency / stream.mix_rate
var phase := 0.0

for i in range(int(stream.mix_rate * duration)):
    var sample := sin(phase * TAU)
    playback.push_frame(Vector2(sample, sample))  # Stereo
    phase += increment
    phase = fmod(phase, 1.0)

return stream
func create_beep(frequency: float, duration: float) -> AudioStreamGenerator: var stream := AudioStreamGenerator.new() stream.mix_rate = 44100 # 采样率
var playback := stream.instantiate_playback()

var increment := frequency / stream.mix_rate
var phase := 0.0

for i in range(int(stream.mix_rate * duration)):
    var sample := sin(phase * TAU)
    playback.push_frame(Vector2(sample, sample))  # 立体声
    phase += increment
    phase = fmod(phase, 1.0)

return stream

Usage:

使用方式:

var beep_stream := create_beep(440.0, 0.1) # 440 Hz (A4), 0.1s $AudioStreamPlayer.stream = beep_stream $AudioStreamPlayer.play()

---
var beep_stream := create_beep(440.0, 0.1) # 440Hz(A4音),0.1秒 $AudioStreamPlayer.stream = beep_stream $AudioStreamPlayer.play()

---

Advanced Patterns

进阶方案

Audio Ducking (Lower Music During Dialogue)

音频闪避(对话时降低音乐音量)

gdscript
undefined
gdscript
undefined

auto_duck.gd (on Dialogue AudioStreamPlayer)

auto_duck.gd(挂载在对话用的AudioStreamPlayer上)

extends AudioStreamPlayer
func _ready() -> void: playing.connect(_on_playing) finished.connect(_on_finished)
func _on_playing() -> void: # Duck music to -15 dB var music_bus := AudioServer.get_bus_index("Music") var tween := create_tween() tween.tween_method(set_music_volume, 0.0, -15.0, 0.5)
func _on_finished() -> void: # Restore music to 0 dB var tween := create_tween() tween.tween_method(set_music_volume, -15.0, 0.0, 0.5)
func set_music_volume(db: float) -> void: var music_bus := AudioServer.get_bus_index("Music") AudioServer.set_bus_volume_db(music_bus, db)
undefined
extends AudioStreamPlayer
func _ready() -> void: playing.connect(_on_playing) finished.connect(_on_finished)
func _on_playing() -> void: # 将音乐音量降低到-15分贝 var music_bus := AudioServer.get_bus_index("Music") var tween := create_tween() tween.tween_method(set_music_volume, 0.0, -15.0, 0.5)
func _on_finished() -> void: # 将音乐音量恢复到0分贝 var tween := create_tween() tween.tween_method(set_music_volume, -15.0, 0.0, 0.5)
func set_music_volume(db: float) -> void: var music_bus := AudioServer.get_bus_index("Music") AudioServer.set_bus_volume_db(music_bus, db)
undefined

Randomize Pitch for Variation

随机音高变化实现音效多样性

gdscript
undefined
gdscript
undefined

Prevent identical sounds (footsteps, gunshots)

避免音效重复(如脚步声、枪声)

func play_varied_sound(stream: AudioStream) -> void: $AudioStreamPlayer.stream = stream $AudioStreamPlayer.pitch_scale = randf_range(0.9, 1.1) # ±10% pitch $AudioStreamPlayer.play()
undefined
func play_varied_sound(stream: AudioStream) -> void: $AudioStreamPlayer.stream = stream $AudioStreamPlayer.pitch_scale = randf_range(0.9, 1.1) # ±10%的音高变化 $AudioStreamPlayer.play()
undefined

Layered Music (Adaptive)

分层音乐(自适应)

gdscript
undefined
gdscript
undefined

Intensity-based music layers (start quiet, add layers as intensity increases)

基于强度的分层音乐(初始安静,强度增加时添加轨道)

Example: Peaceful exploration → Combat

示例:和平探索 → 战斗

@onready var layer_drums := $Music/Drums @onready var layer_bass := $Music/Bass @onready var layer_melody := $Music/Melody
var intensity := 0.0 # 0.0 = calm, 1.0 = intense
func _ready() -> void: # Start all layers in sync layer_drums.play() layer_bass.play() layer_melody.play()
# Mute high-intensity layers
layer_bass.volume_db = -80
layer_melody.volume_db = -80
func set_music_intensity(new_intensity: float) -> void: intensity = clamp(new_intensity, 0.0, 1.0)
# Fade in layers based on intensity
var tween := create_tween().set_parallel(true)

# Layer 1 (drums): always audible
tween.tween_property(layer_drums, "volume_db", 0, 1.0)

# Layer 2 (bass): fade in at 33% intensity
var bass_db := -80 if intensity < 0.33 else lerp(-80.0, 0.0, (intensity - 0.33) / 0.67)
tween.tween_property(layer_bass, "volume_db", bass_db, 1.0)

# Layer 3 (melody): fade in at 66% intensity
var melody_db := -80 if intensity < 0.66 else lerp(-80.0, 0.0, (intensity - 0.66) / 0.34)
tween.tween_property(layer_melody, "volume_db", melody_db, 1.0)
@onready var layer_drums := $Music/Drums @onready var layer_bass := $Music/Bass @onready var layer_melody := $Music/Melody
var intensity := 0.0 # 0.0 = 平静,1.0 = 激烈
func _ready() -> void: # 同步启动所有轨道 layer_drums.play() layer_bass.play() layer_melody.play()
# 静音高强度轨道
layer_bass.volume_db = -80
layer_melody.volume_db = -80
func set_music_intensity(new_intensity: float) -> void: intensity = clamp(new_intensity, 0.0, 1.0)
# 根据强度淡入轨道
var tween := create_tween().set_parallel(true)

# 轨道1(鼓点):始终可闻
tween.tween_property(layer_drums, "volume_db", 0, 1.0)

# 轨道2(贝斯):强度达到33%时淡入
var bass_db := -80 if intensity < 0.33 else lerp(-80.0, 0.0, (intensity - 0.33) / 0.67)
tween.tween_property(layer_bass, "volume_db", bass_db, 1.0)

# 轨道3(旋律):强度达到66%时淡入
var melody_db := -80 if intensity < 0.66 else lerp(-80.0, 0.0, (intensity - 0.66) / 0.34)
tween.tween_property(layer_melody, "volume_db", melody_db, 1.0)

Usage (combat system):

使用方式(战斗系统中):

func _on_enemy_spotted() -> void: MusicManager.set_music_intensity(1.0) # Full intensity
func _on_all_enemies_defeated() -> void: MusicManager.set_music_intensity(0.0) # Back to calm

---
func _on_enemy_spotted() -> void: MusicManager.set_music_intensity(1.0) # 最高强度
func _on_all_enemies_defeated() -> void: MusicManager.set_music_intensity(0.0) # 恢复平静

---

Performance Optimization

性能优化

Disable Far Audio

禁用远处音频

gdscript
undefined
gdscript
undefined

Don't play sounds the player can't hear

不播放玩家听不到的音效

extends AudioStreamPlayer3D
func _process(delta: float) -> void: var listener := get_viewport().get_camera_3d() if not listener: return
var distance := global_position.distance_to(listener.global_position)

if distance > max_distance * 1.5:  # 1.5x max range
    if playing:
        stop()

---
extends AudioStreamPlayer3D
func _process(delta: float) -> void: var listener := get_viewport().get_camera_3d() if not listener: return
var distance := global_position.distance_to(listener.global_position)

if distance > max_distance * 1.5:  # 最大范围的1.5倍
    if playing:
        stop()

---

Edge Cases

边缘情况

Audio Doesn't Play

音频无法播放

gdscript
undefined
gdscript
undefined

Check:

检查项:

1. Is stream assigned?

1. 是否已分配流?

if not $AudioStreamPlayer.stream: push_error("No audio stream assigned!")
if not $AudioStreamPlayer.stream: push_error("未分配音频流!")

2. Is bus muted?

2. 总线是否被静音?

var bus_idx := AudioServer.get_bus_index($AudioStreamPlayer.bus) if AudioServer.is_bus_mute(bus_idx): print("Bus is muted!")
var bus_idx := AudioServer.get_bus_index($AudioStreamPlayer.bus) if AudioServer.is_bus_mute(bus_idx): print("总线已静音!")

3. Is volume too low?

3. 音量是否过低?

if $AudioStreamPlayer.volume_db < -60: print("Volume too quiet (< -60 dB)")

---
if $AudioStreamPlayer.volume_db < -60: print("音量过小(< -60分贝)")

---

Decision Matrix: Which AudioStreamPlayer?

决策矩阵:选择哪种AudioStreamPlayer?

FeatureAudioStreamPlayerAudioStreamPlayer2DAudioStreamPlayer3D
Spatial❌ Global✅ 2D panning✅ 3D positioning
Doppler
Attenuation✅ Distance-based✅ 3D falloff
Reverb send
Use forMusic, UI2D games3D games
PerformanceFastestMediumSlowest
特性AudioStreamPlayerAudioStreamPlayer2DAudioStreamPlayer3D
空间定位❌ 全局✅ 2D声像✅ 3D定位
多普勒效应
衰减✅ 基于距离✅ 3D衰减
混响发送
适用场景音乐、UI2D游戏3D游戏
性能最快中等最慢

Reference

参考

  • Master Skill: godot-master
  • 核心技能:godot-master