Files
step3/scripts/autoload/ui_sound_service.gd
2026-07-11 12:59:17 -05:00

133 lines
3.6 KiB
GDScript

extends Node
const SETTINGS_PATH := "user://settings.cfg"
const SETTINGS_SECTION := "audio"
const SETTINGS_KEY := "ui_sounds_enabled"
const PLAYER_COUNT := 8
const DEFAULT_VOLUME_DB := -12.0
const SOUND_PATHS := {
"click": "res://assets/audio/kenney_interface_sounds/click_003.ogg",
"select": "res://assets/audio/kenney_interface_sounds/select_003.ogg",
"toggle": "res://assets/audio/kenney_interface_sounds/toggle_002.ogg",
"eliminate": "res://assets/audio/kenney_interface_sounds/scratch_002.ogg",
"open": "res://assets/audio/kenney_interface_sounds/open_001.ogg",
"close": "res://assets/audio/kenney_interface_sounds/close_002.ogg",
"correct": "res://assets/audio/kenney_interface_sounds/confirmation_002.ogg",
"error": "res://assets/audio/kenney_interface_sounds/error_004.ogg",
"back": "res://assets/audio/kenney_interface_sounds/back_002.ogg",
"question": "res://assets/audio/kenney_interface_sounds/question_001.ogg"
}
var sounds := {}
var players: Array[AudioStreamPlayer] = []
var sounds_enabled := true
var next_player_index := 0
func _ready() -> void:
_load_setting()
_load_sounds()
_build_player_pool()
get_tree().node_added.connect(_on_node_added)
call_deferred("_wire_existing_buttons")
func play_sound(sound_name: String) -> void:
if not sounds_enabled or not sounds.has(sound_name) or players.is_empty():
return
var player := _next_available_player()
player.stream = sounds[sound_name]
player.play()
func set_sounds_enabled(is_enabled: bool) -> void:
if sounds_enabled == is_enabled:
return
sounds_enabled = is_enabled
if not sounds_enabled:
for player in players:
player.stop()
_save_setting()
if sounds_enabled:
play_sound("toggle")
func are_sounds_enabled() -> bool:
return sounds_enabled
func set_button_sound(button: Button, sound_name: String) -> void:
button.set_meta("ui_sound", sound_name)
_wire_button(button)
func _load_sounds() -> void:
for sound_name in SOUND_PATHS:
var stream := load(str(SOUND_PATHS[sound_name])) as AudioStream
if stream != null:
sounds[sound_name] = stream
else:
push_warning("Unable to load UI sound: %s" % SOUND_PATHS[sound_name])
func _build_player_pool() -> void:
for _player_index in range(PLAYER_COUNT):
var player := AudioStreamPlayer.new()
player.volume_db = DEFAULT_VOLUME_DB
add_child(player)
players.append(player)
func _next_available_player() -> AudioStreamPlayer:
for player in players:
if not player.playing:
return player
var player := players[next_player_index]
next_player_index = (next_player_index + 1) % players.size()
return player
func _on_node_added(node: Node) -> void:
call_deferred("_wire_node", node)
func _wire_existing_buttons() -> void:
_wire_node(get_tree().root)
func _wire_node(node: Node) -> void:
if not is_instance_valid(node):
return
if node is Button:
_wire_button(node)
for child in node.get_children():
_wire_node(child)
func _wire_button(button: Button) -> void:
if button.has_meta("ui_sound_wired"):
return
button.set_meta("ui_sound_wired", true)
button.pressed.connect(_on_button_pressed.bind(button))
func _on_button_pressed(button: Button) -> void:
var sound_name := str(button.get_meta("ui_sound", "click"))
if sound_name != "none":
play_sound(sound_name)
func _load_setting() -> void:
var config := ConfigFile.new()
if config.load(SETTINGS_PATH) == OK:
sounds_enabled = bool(config.get_value(SETTINGS_SECTION, SETTINGS_KEY, true))
func _save_setting() -> void:
var config := ConfigFile.new()
config.load(SETTINGS_PATH)
config.set_value(SETTINGS_SECTION, SETTINGS_KEY, sounds_enabled)
var save_error := config.save(SETTINGS_PATH)
if save_error != OK:
push_warning("Unable to save UI sound preference.")