class_name BallSFX extends Node3D ## Controller for ball sound effects. const BASE_VOLUME := -36.0 const MAX_VOLUME := 3.0 const VELOCITY_ATTENUATION_SCALE := 400.0 const GRASS_PHYSICAL_LAYER := 1 << 32 const SAND_PHYSICAL_LAYER := 1 << 31 @onready var parent: GameBall = $".." @onready var grass_sfx_player: AudioStreamPlayer3D = %GrassSFXPlayer @onready var concrete_sfx_player: AudioStreamPlayer3D = %ConcreteSFXPlayer @onready var sand_sfx_player: AudioStreamPlayer3D = %SandSFXPlayer func _force_attenuated_volume() -> float: # Attenuate volume based on impact force return lerpf( BASE_VOLUME, MAX_VOLUME, clampf(parent.linear_velocity.length_squared() / VELOCITY_ATTENUATION_SCALE, 0, 1) ) func _play_sfx(player: AudioStreamPlayer3D) -> void: player.volume_db = _force_attenuated_volume() print("PLAYING: ", player, "... VOLUME: ", player.volume_db) player.play() func play_terrain_sfx(tex_id: int) -> void: var player := grass_sfx_player match tex_id: 2: # sand player = sand_sfx_player 3: # rock player = concrete_sfx_player _play_sfx(player) ## Select the appropriate SFX to play based on the collision layer of the collider. ## ## We use the upper bits of the collision layer to indicate standard SFX. func play_physical_sfx(collision_mask: int) -> void: var player := concrete_sfx_player if collision_mask & GRASS_PHYSICAL_LAYER: player = grass_sfx_player elif collision_mask & SAND_PHYSICAL_LAYER: player = sand_sfx_player _play_sfx(player)