class_name FootstepController extends Node3D const BASE_VOLUME := -42.0 const MUTE_VELOCITY := 1.0 const VELOCITY_FACTOR := 2.0 var _on_right_foot := false @onready var left_foot: FootController = %LeftFoot @onready var right_foot: FootController = %RightFoot @onready var foot_cast: RayCast3D = %FootCast @onready var footstep_game_sound_emitter: GameSoundEmitter = %FootstepGameSoundEmitter func play_footstep() -> void: if Player.instance.sneaking: return var foot := right_foot if _on_right_foot else left_foot var relative_speed := Player.instance.velocity.length() - MUTE_VELOCITY if relative_speed < 0: return var sfx := foot.get_player_for_material(get_material_under_foot()) if sfx: sfx.volume_db = BASE_VOLUME + relative_speed * VELOCITY_FACTOR sfx.play() footstep_game_sound_emitter.emit_sound_here() _on_right_foot = not _on_right_foot func get_material_under_foot() -> SurfaceMaterial.Type: var collider := foot_cast.get_collider() as Node if collider is GunkBody: # Special case: check if collision surface is gunked if (collider as GunkBody).is_point_gunked( foot_cast.get_collision_point(), foot_cast.get_collision_normal() ): return SurfaceMaterial.Type.GRUNK return SurfaceMaterial.material_for_collider(collider)