Audio manager implementation
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-1
@@ -23,8 +23,9 @@ config/icon="res://assets/icon.svg"
|
||||
|
||||
# ===== AUTOLOAD INITIALIZATION ORDER =====
|
||||
# Order is critical! Dependencies must load before dependents.
|
||||
# Layer 0: Event system (no dependencies)
|
||||
# Layer 0: Core systems (no dependencies)
|
||||
EventBus="*res://scripts/event_bus.gd"
|
||||
AudioManager="*res://scripts/autoload/audio_manager.gd"
|
||||
# Layer 1: Core managers (depend on EventBus only)
|
||||
GameManager="*res://scripts/game_manager.gd"
|
||||
SaveManager="*res://scripts/save_manager.gd"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
extends Node
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AudioManager — singleton for playing sound effects
|
||||
# Uses a pool of AudioStreamPlayers to allow overlapping sounds
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
const POOL_SIZE := 8
|
||||
|
||||
# Preloaded sound effects
|
||||
var _sounds: Dictionary = {
|
||||
"enemy_hit": preload("res://assets/audio/sfx/enemy_hit.wav"),
|
||||
"player_hit": preload("res://assets/audio/sfx/player_hit.wav"),
|
||||
"player_shoot": preload("res://assets/audio/sfx/player_shoot.wav"),
|
||||
"explosion": preload("res://assets/audio/sfx/explosion.wav"),
|
||||
"pickup_scrap": preload("res://assets/audio/sfx/pickup_scrap.wav"),
|
||||
"item_pickup": preload("res://assets/audio/sfx/item_pickup.wav"),
|
||||
"ui_click": preload("res://assets/audio/sfx/ui_click.wav"),
|
||||
"ui_select": preload("res://assets/audio/sfx/ui_select.wav"),
|
||||
}
|
||||
|
||||
var _pool: Array[AudioStreamPlayer] = []
|
||||
var _pool_index: int = 0
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
for i in POOL_SIZE:
|
||||
var player := AudioStreamPlayer.new()
|
||||
player.bus = "Master"
|
||||
add_child(player)
|
||||
_pool.append(player)
|
||||
|
||||
func play(sound_name: String) -> void:
|
||||
if not _sounds.has(sound_name):
|
||||
push_warning("AudioManager: Unknown sound '%s'" % sound_name)
|
||||
return
|
||||
|
||||
var player := _pool[_pool_index]
|
||||
_pool_index = (_pool_index + 1) % POOL_SIZE
|
||||
|
||||
player.stream = _sounds[sound_name]
|
||||
player.play()
|
||||
@@ -24,5 +24,6 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
if body.is_in_group("player"):
|
||||
AudioManager.play("pickup_scrap")
|
||||
RunManager.earn_credits(value)
|
||||
queue_free()
|
||||
@@ -86,6 +86,7 @@ func get_slow_factor() -> float:
|
||||
func take_damage(amount: float) -> void:
|
||||
current_health -= amount
|
||||
_flash_timer = 0.1
|
||||
AudioManager.play("enemy_hit")
|
||||
if current_health <= 0.0:
|
||||
_die()
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ func _draw() -> void:
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
if not body.is_in_group("player") or item == null:
|
||||
return
|
||||
AudioManager.play("item_pickup")
|
||||
RunManager.collect_item(item) # Triggers item_collected signal -> player_stats recalculates
|
||||
if item.heal_on_pickup > 0.0:
|
||||
body.stats.heal(item.heal_on_pickup)
|
||||
|
||||
@@ -68,6 +68,7 @@ func _attempt_purchase() -> void:
|
||||
return
|
||||
|
||||
RunManager.spend_credits(price)
|
||||
AudioManager.play("item_pickup")
|
||||
|
||||
var player := get_tree().get_first_node_in_group("player") as Node2D
|
||||
if player == null:
|
||||
|
||||
@@ -94,6 +94,7 @@ func _handle_shooting(delta: float) -> void:
|
||||
_shoot_timer = 1.0 / stats.fire_rate
|
||||
|
||||
func _fire(direction: Vector2) -> void:
|
||||
AudioManager.play("player_shoot")
|
||||
# Overclock: every 3rd shot deals 0 damage
|
||||
var is_zeroed_shot := false
|
||||
if stats.overclock:
|
||||
@@ -201,6 +202,7 @@ func take_damage(amount: float) -> void:
|
||||
|
||||
stats.current_health -= actual
|
||||
_iframe_timer = IFRAME_DURATION
|
||||
AudioManager.play("player_hit")
|
||||
EventBus.player_health_changed.emit(stats.current_health, stats.max_health)
|
||||
|
||||
# Reactive effects on taking damage
|
||||
|
||||
@@ -76,6 +76,7 @@ func _on_body_entered(body: Node) -> void:
|
||||
# Explosive — AoE damage to all enemies in radius
|
||||
# ---------------------------------------------------------------------------
|
||||
func _explode() -> void:
|
||||
AudioManager.play("explosion")
|
||||
var space := get_world_2d().direct_space_state
|
||||
var query := PhysicsShapeQueryParameters2D.new()
|
||||
var circle := CircleShape2D.new()
|
||||
|
||||
@@ -82,13 +82,16 @@ func _input(event: InputEvent) -> void:
|
||||
|
||||
if event.is_action_pressed("ui_up"):
|
||||
_cursor = wrapi(_cursor - 1, 0, maxi(1, _items.size()))
|
||||
AudioManager.play("ui_select")
|
||||
_refresh_labels()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ui_down"):
|
||||
_cursor = wrapi(_cursor + 1, 0, maxi(1, _items.size()))
|
||||
AudioManager.play("ui_select")
|
||||
_refresh_labels()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ui_accept"):
|
||||
AudioManager.play("ui_click")
|
||||
_equip_selected()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ui_cancel"):
|
||||
|
||||
@@ -113,24 +113,24 @@ func _build_ui() -> void:
|
||||
|
||||
var dep_btn := Button.new()
|
||||
dep_btn.text = "DEPOSIT\n(ON HAND → BANK)"
|
||||
dep_btn.pressed.connect(_on_deposit)
|
||||
dep_btn.pressed.connect(func(): AudioManager.play("ui_click"); _on_deposit())
|
||||
action_row.add_child(dep_btn)
|
||||
|
||||
var wth_btn := Button.new()
|
||||
wth_btn.text = "WITHDRAW\n(BANK → ON HAND)"
|
||||
wth_btn.pressed.connect(_on_withdraw)
|
||||
wth_btn.pressed.connect(func(): AudioManager.play("ui_click"); _on_withdraw())
|
||||
action_row.add_child(wth_btn)
|
||||
|
||||
# Close
|
||||
var close_btn := Button.new()
|
||||
close_btn.text = "CLOSE"
|
||||
close_btn.pressed.connect(close)
|
||||
close_btn.pressed.connect(func(): AudioManager.play("ui_click"); close())
|
||||
vbox.add_child(close_btn)
|
||||
|
||||
func _add_btn(parent: Node, text: String, cb: Callable) -> void:
|
||||
var b := Button.new()
|
||||
b.text = text
|
||||
b.pressed.connect(cb)
|
||||
b.pressed.connect(func(): AudioManager.play("ui_click"); cb.call())
|
||||
parent.add_child(b)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -43,7 +43,7 @@ func _add_button(parent: Node, text: String, callback: Callable) -> void:
|
||||
var btn := Button.new()
|
||||
btn.text = text
|
||||
btn.custom_minimum_size = Vector2(240, 48)
|
||||
btn.pressed.connect(callback)
|
||||
btn.pressed.connect(func(): AudioManager.play("ui_click"); callback.call())
|
||||
parent.add_child(btn)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -53,7 +53,7 @@ func _show_victory() -> void:
|
||||
var btn := Button.new()
|
||||
btn.text = "RETURN TO HUB"
|
||||
btn.position = Vector2(-80, 70)
|
||||
btn.pressed.connect(_fade_out_then_hub)
|
||||
btn.pressed.connect(func(): AudioManager.play("ui_click"); _fade_out_then_hub())
|
||||
_root.add_child(btn)
|
||||
|
||||
_fade_in()
|
||||
|
||||
@@ -7,5 +7,6 @@ func _ready() -> void:
|
||||
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
if body.is_in_group("player") and part != null:
|
||||
AudioManager.play("item_pickup")
|
||||
UpgradeManager.acquire_part(part)
|
||||
queue_free()
|
||||
|
||||
Reference in New Issue
Block a user