Audio
Muziek, geluidseffecten, en audio management.
Overzicht
┌─────────────────────────────────────────────────────────────────┐
│ Audio Systeem │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Audio Buses: │
│ ├── Master │
│ │ ├── Music (achtergrondmuziek) │
│ │ ├── SFX (geluidseffecten) │
│ │ ├── UI (interface sounds) │
│ │ └── Ambient (omgevingsgeluiden) │
│ │
│ File Formats: │
│ ├── Music: OGG Vorbis (streaming) │
│ ├── SFX: WAV (low latency) │
│ └── Ambient: OGG Vorbis (looping) │
│ │
└─────────────────────────────────────────────────────────────────┘
Audio Manager
# audio_manager.gd (autoload)
extends Node
# Bus indices
var _music_bus: int
var _sfx_bus: int
var _ui_bus: int
var _ambient_bus: int
# Players
@onready var music_player: AudioStreamPlayer = $MusicPlayer
@onready var ambient_player: AudioStreamPlayer = $AmbientPlayer
var _sfx_pool: Array[AudioStreamPlayer] = []
const SFX_POOL_SIZE = 8
const FADE_DURATION = 1.0
func _ready() -> void:
_music_bus = AudioServer.get_bus_index("Music")
_sfx_bus = AudioServer.get_bus_index("SFX")
_ui_bus = AudioServer.get_bus_index("UI")
_ambient_bus = AudioServer.get_bus_index("Ambient")
_create_sfx_pool()
_load_settings()
func _create_sfx_pool() -> void:
for i in range(SFX_POOL_SIZE):
var player = AudioStreamPlayer.new()
player.bus = "SFX"
add_child(player)
_sfx_pool.append(player)
Muziek Systeem
Afspelen met Crossfade
var current_music: String = ""
var music_tween: Tween = null
func play_music(track_name: String, fade: bool = true) -> void:
if track_name == current_music:
return
var stream = _load_music(track_name)
if not stream:
push_error("Music not found: " + track_name)
return
current_music = track_name
if fade and music_player.playing:
_crossfade_to(stream)
else:
music_player.stream = stream
music_player.play()
func _crossfade_to(new_stream: AudioStream) -> void:
if music_tween:
music_tween.kill()
# Create second player for crossfade
var new_player = AudioStreamPlayer.new()
new_player.stream = new_stream
new_player.bus = "Music"
new_player.volume_db = -80
add_child(new_player)
new_player.play()
music_tween = create_tween()
music_tween.set_parallel(true)
# Fade out old
music_tween.tween_property(music_player, "volume_db", -80, FADE_DURATION)
# Fade in new
music_tween.tween_property(new_player, "volume_db", 0, FADE_DURATION)
music_tween.chain().tween_callback(func():
music_player.stop()
music_player.stream = new_stream
music_player.volume_db = 0
music_player.play()
music_player.seek(new_player.get_playback_position())
new_player.queue_free()
)
func _load_music(track_name: String) -> AudioStream:
var path = "res://assets/audio/music/%s.ogg" % track_name
if ResourceLoader.exists(path):
return load(path)
return null
Scene Music
# Automatische muziek per scene
const SCENE_MUSIC = {
"main_menu": "menu_theme",
"treehouse": "cozy_home",
"garden": "nature_morning",
"world_map": "adventure",
"shop": "cheerful_shop"
}
func _on_scene_changed(scene_name: String) -> void:
if scene_name in SCENE_MUSIC:
play_music(SCENE_MUSIC[scene_name])
Geluidseffecten
SFX Afspelen
const SFX_LIBRARY = {
# UI
"button_click": "res://assets/audio/sfx/ui/click.wav",
"button_hover": "res://assets/audio/sfx/ui/hover.wav",
"panel_open": "res://assets/audio/sfx/ui/panel_open.wav",
"panel_close": "res://assets/audio/sfx/ui/panel_close.wav",
"notification": "res://assets/audio/sfx/ui/notification.wav",
# Gameplay
"plant_seed": "res://assets/audio/sfx/gameplay/plant.wav",
"harvest": "res://assets/audio/sfx/gameplay/harvest.wav",
"water_splash": "res://assets/audio/sfx/gameplay/water.wav",
"pickup_item": "res://assets/audio/sfx/gameplay/pickup.wav",
"level_up": "res://assets/audio/sfx/gameplay/level_up.wav",
# Pets
"cat_meow": "res://assets/audio/sfx/pets/cat_meow.wav",
"dog_bark": "res://assets/audio/sfx/pets/dog_bark.wav",
"pet_happy": "res://assets/audio/sfx/pets/happy.wav",
# Footsteps
"step_grass": "res://assets/audio/sfx/footsteps/grass.wav",
"step_wood": "res://assets/audio/sfx/footsteps/wood.wav",
"step_stone": "res://assets/audio/sfx/footsteps/stone.wav"
}
func play_sound(sound_name: String, volume_db: float = 0.0) -> void:
if sound_name not in SFX_LIBRARY:
push_warning("SFX not found: " + sound_name)
return
var player = _get_available_sfx_player()
if not player:
return
player.stream = load(SFX_LIBRARY[sound_name])
player.volume_db = volume_db
player.play()
func _get_available_sfx_player() -> AudioStreamPlayer:
for player in _sfx_pool:
if not player.playing:
return player
# All busy, use first one
return _sfx_pool[0]
Positional Audio
func play_sound_at(sound_name: String, position: Vector2, max_distance: float = 500.0) -> void:
var player = AudioStreamPlayer2D.new()
player.stream = load(SFX_LIBRARY[sound_name])
player.bus = "SFX"
player.max_distance = max_distance
player.global_position = position
player.finished.connect(player.queue_free)
get_tree().current_scene.add_child(player)
player.play()
Random Pitch Variation
func play_sound_varied(sound_name: String, pitch_range: float = 0.1) -> void:
var player = _get_available_sfx_player()
if not player:
return
player.stream = load(SFX_LIBRARY[sound_name])
player.pitch_scale = randf_range(1.0 - pitch_range, 1.0 + pitch_range)
player.play()
# Voorbeeld: voetstappen met variatie
func play_footstep(surface: String) -> void:
play_sound_varied("step_" + surface, 0.15)
Ambient Audio
Omgevingsgeluiden
const AMBIENT_LAYERS = {
"treehouse": [
{"stream": "birds_chirping", "volume": -10},
{"stream": "wind_light", "volume": -15}
],
"garden": [
{"stream": "birds_chirping", "volume": -5},
{"stream": "insects", "volume": -12},
{"stream": "wind_leaves", "volume": -8}
],
"night": [
{"stream": "crickets", "volume": -8},
{"stream": "owl_distant", "volume": -20}
]
}
var ambient_players: Array[AudioStreamPlayer] = []
func set_ambient(preset: String) -> void:
# Stop current ambient
for player in ambient_players:
player.queue_free()
ambient_players.clear()
if preset not in AMBIENT_LAYERS:
return
# Start new layers
for layer in AMBIENT_LAYERS[preset]:
var player = AudioStreamPlayer.new()
player.stream = load("res://assets/audio/ambient/%s.ogg" % layer.stream)
player.bus = "Ambient"
player.volume_db = layer.volume
player.autoplay = true
add_child(player)
ambient_players.append(player)
Day/Night Transition
func transition_ambient(from: String, to: String, duration: float = 3.0) -> void:
var old_players = ambient_players.duplicate()
ambient_players.clear()
# Fade in new ambient
if to in AMBIENT_LAYERS:
for layer in AMBIENT_LAYERS[to]:
var player = AudioStreamPlayer.new()
player.stream = load("res://assets/audio/ambient/%s.ogg" % layer.stream)
player.bus = "Ambient"
player.volume_db = -80
add_child(player)
player.play()
ambient_players.append(player)
var tween = create_tween()
tween.tween_property(player, "volume_db", layer.volume, duration)
# Fade out old ambient
for player in old_players:
var tween = create_tween()
tween.tween_property(player, "volume_db", -80, duration)
tween.tween_callback(player.queue_free)
Volume Controle
func set_music_volume(value: float) -> void:
# value: 0.0 - 1.0
var db = linear_to_db(value)
AudioServer.set_bus_volume_db(_music_bus, db)
func set_sfx_volume(value: float) -> void:
var db = linear_to_db(value)
AudioServer.set_bus_volume_db(_sfx_bus, db)
func set_master_volume(value: float) -> void:
var db = linear_to_db(value)
AudioServer.set_bus_volume_db(0, db) # Master bus
func mute(bus_name: String, muted: bool) -> void:
var bus_idx = AudioServer.get_bus_index(bus_name)
AudioServer.set_bus_mute(bus_idx, muted)
func _load_settings() -> void:
var settings = Settings.load_settings()
set_music_volume(settings.music_volume)
set_sfx_volume(settings.sfx_volume)
Audio Specificaties
Muziek
| Track | Formaat | Bitrate | Loop | Duur |
|---|---|---|---|---|
| menu_theme | OGG | 192kbps | Yes | 2:00 |
| cozy_home | OGG | 192kbps | Yes | 3:00 |
| nature_morning | OGG | 192kbps | Yes | 2:30 |
| adventure | OGG | 192kbps | Yes | 2:30 |
| night_peaceful | OGG | 192kbps | Yes | 3:00 |
SFX
| Effect | Formaat | Sample Rate | Lengte |
|---|---|---|---|
| button_click | WAV | 44.1kHz | <0.1s |
| harvest | WAV | 44.1kHz | 0.5s |
| level_up | WAV | 44.1kHz | 1.5s |
| footstep | WAV | 44.1kHz | <0.2s |
Ambient
| Layer | Formaat | Loop Point | Volume |
|---|---|---|---|
| birds_chirping | OGG | Seamless | -10dB |
| wind_light | OGG | Seamless | -15dB |
| crickets | OGG | Seamless | -8dB |