Audio manager implementation
This commit is contained in:
@@ -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