godot-audio-systems
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAudio 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 — expects decibels (-80 to 0). Use
set_bus_volume_db()for 0.0-1.0 conversion.linear_to_db() - NEVER forget to set on music players — Music autoplays on scene load by default. Causes overlapping tracks when changing scenes.
autoplay = false - NEVER use AudioStreamPlayer3D without attenuation model — Default attenuation is NONE (no falloff). Set to ATTENUATION_INVERSE_DISTANCE or audio is global.
attenuation_model - NEVER play AudioStreamPlayer without checking first — Restarting an already-playing sound cuts it off. Check
playingbefore play().if not player.playing:
- 绝对不要为每个音效创建新的AudioStreamPlayer节点——这会导致内存膨胀和GC峰值。请使用音频池(复用播放器)或一次性辅助函数。
- 绝对不要用线性值设置AudioServer总线音量——需要传入分贝值(范围-80到0)。使用
set_bus_volume_db()将0.0-1.0的线性值转换为分贝。linear_to_db() - 绝对不要忘记给音乐播放器设置——音乐播放器默认会在场景加载时自动播放,切换场景时会导致音轨重叠。
autoplay = false - 绝对不要在未设置衰减模型的情况下使用AudioStreamPlayer3D——默认衰减模式为NONE(无衰减)。请将设置为ATTENUATION_INVERSE_DISTANCE,否则音频会全局播放。
attenuation_model - 绝对不要在未检查状态的情况下播放AudioStreamPlayer——重启正在播放的音效会打断它。播放前请检查
playing。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
undefinedgdscript
undefinedNo 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()
undefinedAudioStreamPlayer2D (Positional)
AudioStreamPlayer2D(位置音频)
gdscript
undefinedgdscript
undefined2D 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()
undefinedextends 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()
undefinedAudioStreamPlayer3D (Spatial)
AudioStreamPlayer3D(空间音频)
gdscript
undefinedgdscript
undefined3D 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
undefinedgdscript
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))
undefinedvar current_db := AudioServer.get_bus_volume_db(music_bus)
var linear := db_to_linear(current_db)
print("当前音量:%d%%" % int(linear * 100))
undefinedMute 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
undefinedgdscript
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!
undefinedfunc 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个节点!
undefinedSolution: Audio Pool
解决方案:音频池
gdscript
undefinedgdscript
undefinedaudio_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
undefinedgdscript
undefinedmusic_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_trackundefinedextends 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_trackundefinedBPM-Synced Transitions
BPM同步过渡
gdscript
undefinedgdscript
undefinedTransition 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
undefinedgdscript
undefinedAdd 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)
undefinedvar 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)
undefinedUnderwater 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
undefinedgdscript
undefinedGenerate 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 streamfunc 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 streamUsage:
使用方式:
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
undefinedgdscript
undefinedauto_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)
undefinedextends 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)
undefinedRandomize Pitch for Variation
随机音高变化实现音效多样性
gdscript
undefinedgdscript
undefinedPrevent 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()
undefinedfunc play_varied_sound(stream: AudioStream) -> void:
$AudioStreamPlayer.stream = stream
$AudioStreamPlayer.pitch_scale = randf_range(0.9, 1.1) # ±10%的音高变化
$AudioStreamPlayer.play()
undefinedLayered Music (Adaptive)
分层音乐(自适应)
gdscript
undefinedgdscript
undefinedIntensity-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 = -80func 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 = -80func 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
undefinedgdscript
undefinedDon'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
undefinedgdscript
undefinedCheck:
检查项:
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?
| Feature | AudioStreamPlayer | AudioStreamPlayer2D | AudioStreamPlayer3D |
|---|---|---|---|
| Spatial | ❌ Global | ✅ 2D panning | ✅ 3D positioning |
| Doppler | ❌ | ❌ | ✅ |
| Attenuation | ❌ | ✅ Distance-based | ✅ 3D falloff |
| Reverb send | ❌ | ❌ | ✅ |
| Use for | Music, UI | 2D games | 3D games |
| Performance | Fastest | Medium | Slowest |
| 特性 | AudioStreamPlayer | AudioStreamPlayer2D | AudioStreamPlayer3D |
|---|---|---|---|
| 空间定位 | ❌ 全局 | ✅ 2D声像 | ✅ 3D定位 |
| 多普勒效应 | ❌ | ❌ | ✅ |
| 衰减 | ❌ | ✅ 基于距离 | ✅ 3D衰减 |
| 混响发送 | ❌ | ❌ | ✅ |
| 适用场景 | 音乐、UI | 2D游戏 | 3D游戏 |
| 性能 | 最快 | 中等 | 最慢 |
Reference
参考
- Master Skill: godot-master
- 核心技能:godot-master