From 9156b14dc874719bddc79f3b6032449469fbc364 Mon Sep 17 00:00:00 2001 From: Leonardo-UTP Date: Fri, 18 Sep 2026 22:15:33 -0500 Subject: [PATCH 1/2] Add terrain-based footstep sound system --- .../player/components/footstep_sound.gd | 63 +++++++++++++++++++ .../player/components/footstep_sound.gd.uid | 1 + .../characters/player/player.tscn | 23 ++++++- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 scenes/game_elements/characters/player/components/footstep_sound.gd create mode 100644 scenes/game_elements/characters/player/components/footstep_sound.gd.uid diff --git a/scenes/game_elements/characters/player/components/footstep_sound.gd b/scenes/game_elements/characters/player/components/footstep_sound.gd new file mode 100644 index 000000000..996d3e91c --- /dev/null +++ b/scenes/game_elements/characters/player/components/footstep_sound.gd @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: The Threadbare Authors +# SPDX-License-Identifier: MPL-2.0 +extends Node2D + +@export var sound_for_material: Dictionary[String, AudioStream] + +var _footstep_layers: Array[TileMapLayer] = [] + +@onready var walk_sound: AudioStreamPlayer2D = %WalkSound + +var _default_walk_sound: AudioStream + +## Stores the default footstep sound and caches TileMapLayers whose TileSets +## define a "material" custom data layer. +func _ready() -> void: + _default_walk_sound = walk_sound.stream + + var scene_root := get_tree().current_scene + var tile_map_layers := scene_root.find_children("*", "TileMapLayer", true, false) + + for node in tile_map_layers: + var layer := node as TileMapLayer + if not layer: + continue + + if not layer.tile_set: + continue + + if not layer.tile_set.has_custom_data_layer_by_name("material"): + continue + + _footstep_layers.append(layer) + + +## Detects the terrain material beneath the player and plays its configured +## footstep sound. Falls back to the default sound when no match is configured. +## Called from the footstep frames defined in the walk animation. +func play_footstep() -> void: + if Engine.is_editor_hint(): + return + + var current_footstep_material: String = "" + + for layer in _footstep_layers: + var coord := layer.local_to_map( + layer.to_local(global_position) + ) + var tile_data := layer.get_cell_tile_data(coord) + + if not tile_data: + continue + + var footstep_material: Variant = tile_data.get_custom_data("material") + if footstep_material is String and not footstep_material.is_empty(): + current_footstep_material = footstep_material + + var footstep_sound: AudioStream = sound_for_material.get( + current_footstep_material, + _default_walk_sound + ) + + walk_sound.stream = footstep_sound + walk_sound.play() diff --git a/scenes/game_elements/characters/player/components/footstep_sound.gd.uid b/scenes/game_elements/characters/player/components/footstep_sound.gd.uid new file mode 100644 index 000000000..1910a2fc3 --- /dev/null +++ b/scenes/game_elements/characters/player/components/footstep_sound.gd.uid @@ -0,0 +1 @@ +uid://cvjpavggqssir diff --git a/scenes/game_elements/characters/player/player.tscn b/scenes/game_elements/characters/player/player.tscn index 8c507a27b..c28ae9161 100644 --- a/scenes/game_elements/characters/player/player.tscn +++ b/scenes/game_elements/characters/player/player.tscn @@ -16,6 +16,7 @@ [ext_resource type="PackedScene" uid="uid://b3111eergq5yg" path="res://scenes/game_elements/characters/player/components/player_hook.tscn" id="13_ecbbk"] [ext_resource type="Script" uid="uid://bk52qjv58locq" path="res://scenes/game_logic/light2d_behaviors/artificial_light_behavior.gd" id="16_ecbbk"] [ext_resource type="Texture2D" uid="uid://b5ooaiyxdrp6a" path="res://scenes/game_elements/components/light_texture_256x256.tres" id="16_tnibl"] +[ext_resource type="Script" uid="uid://cvjpavggqssir" path="res://scenes/game_elements/characters/player/components/footstep_sound.gd" id="17_tnibl"] [sub_resource type="Resource" id="Resource_cvb4d"] script = ExtResource("3_cvb4d") @@ -293,11 +294,28 @@ tracks/2/path = NodePath("WalkSound:playing") tracks/2/interp = 1 tracks/2/loop_wrap = true tracks/2/keys = { -"times": PackedFloat32Array(0.115043, 0.4), +"times": PackedFloat32Array(0.115, 0.4), "transitions": PackedFloat32Array(1, 1), "update": 1, "values": [true, true] } +tracks/3/type = "method" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("FootstepSound") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0.115, 0.4), +"transitions": PackedFloat32Array(1, 1), +"values": [{ +"args": [], +"method": &"play_footstep" +}, { +"args": [], +"method": &"play_footstep" +}] +} [sub_resource type="AnimationLibrary" id="AnimationLibrary_qek5x"] _data = { @@ -473,6 +491,9 @@ unique_name_in_owner = true root_node = NodePath("../../PlayerRepel") libraries/ = SubResource("AnimationLibrary_1n58k") +[node name="FootstepSound" type="Node2D" parent="." unique_id=1578687431] +script = ExtResource("17_tnibl") + [connection signal="running_changed" from="InputWalkBehavior" to="PlayerDustParticles" method="set_emitting"] [connection signal="running_changed" from="InputWalkBehavior" to="AnimationPlayer" method="_on_input_walk_behavior_running_changed"] [connection signal="aiming_changed" from="PlayerHook" to="." method="_on_player_hook_aiming_changed"] From f55d3ba7ec4ef8e29a58eb935a67cf5e4187695d Mon Sep 17 00:00:00 2001 From: Leonardo-UTP Date: Mon, 21 Sep 2026 06:47:11 -0500 Subject: [PATCH 2/2] Fix footstep sound formatting --- .../characters/player/components/footstep_sound.gd | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scenes/game_elements/characters/player/components/footstep_sound.gd b/scenes/game_elements/characters/player/components/footstep_sound.gd index 996d3e91c..5bb137568 100644 --- a/scenes/game_elements/characters/player/components/footstep_sound.gd +++ b/scenes/game_elements/characters/player/components/footstep_sound.gd @@ -5,10 +5,10 @@ extends Node2D @export var sound_for_material: Dictionary[String, AudioStream] var _footstep_layers: Array[TileMapLayer] = [] +var _default_walk_sound: AudioStream @onready var walk_sound: AudioStreamPlayer2D = %WalkSound -var _default_walk_sound: AudioStream ## Stores the default footstep sound and caches TileMapLayers whose TileSets ## define a "material" custom data layer. @@ -42,9 +42,7 @@ func play_footstep() -> void: var current_footstep_material: String = "" for layer in _footstep_layers: - var coord := layer.local_to_map( - layer.to_local(global_position) - ) + var coord := layer.local_to_map(layer.to_local(global_position)) var tile_data := layer.get_cell_tile_data(coord) if not tile_data: @@ -55,8 +53,7 @@ func play_footstep() -> void: current_footstep_material = footstep_material var footstep_sound: AudioStream = sound_for_material.get( - current_footstep_material, - _default_walk_sound + current_footstep_material, _default_walk_sound ) walk_sound.stream = footstep_sound