101 lines
3.7 KiB
GDScript
101 lines
3.7 KiB
GDScript
extends Area3D
|
|
|
|
var collider_audio_pair = []
|
|
|
|
@export var rustle_sounds: PackedScene
|
|
@export var placeholder: CollisionShape3D
|
|
|
|
const VELOCITY_ATTENUATION_THRESHOLD = 3.0
|
|
const ATTENUATION_ADJUST_SPEED = 200.0
|
|
const FADE_IN_OUT = 0.15
|
|
|
|
@onready var rustle_sounds_loaded = load(rustle_sounds.resource_path)
|
|
|
|
func _ready():
|
|
placeholder.queue_free()
|
|
var colliders = find_children("*", "CollisionShape3D", true)
|
|
for collider in colliders:
|
|
collider.reparent(self, true)
|
|
|
|
body_entered.connect(_on_body_entered)
|
|
body_exited.connect(_on_body_exited)
|
|
|
|
func _physics_process(delta):
|
|
for pair in collider_audio_pair:
|
|
pair["audio"].global_position = pair["collider"].global_position
|
|
var atten_speed = ATTENUATION_ADJUST_SPEED * delta
|
|
var atten_target = set_atten(pair["collider"], pair["audio"], true)
|
|
if pair["audio"].volume_db > atten_target:
|
|
atten_speed = atten_speed / 3.0
|
|
pair["audio"].volume_db = move_toward(pair["audio"].volume_db, atten_target, atten_speed)
|
|
|
|
# should change to get_atten sometime
|
|
func set_atten(phys_obj, audio, get_vol := false):
|
|
var collider_velocity
|
|
if phys_obj is CharacterBody3D:
|
|
collider_velocity = phys_obj.get_real_velocity().length()
|
|
else:
|
|
if phys_obj.linear_velocity.length() > phys_obj.angular_velocity.length():
|
|
collider_velocity = phys_obj.linear_velocity.length()
|
|
else:
|
|
collider_velocity = phys_obj.angular_velocity.length()
|
|
|
|
var rustle_atten = collider_velocity/VELOCITY_ATTENUATION_THRESHOLD
|
|
rustle_atten = clamp(rustle_atten, 0.0, 1.0)
|
|
|
|
var vol = lerp(-80.0, 0.0, ease_out_circ(rustle_atten))
|
|
if get_vol:
|
|
return vol
|
|
else:
|
|
audio.volume_db = vol
|
|
|
|
func _on_body_entered(body):
|
|
if body is RigidBody3D or CharacterBody3D:
|
|
var rustle_sounds = rustle_sounds_loaded.instantiate()
|
|
get_tree().root.get_child(0).add_child(rustle_sounds)
|
|
|
|
# is this fade in necessary? the move_towards behavior should already act as its own fade in right? only fade out is necessary due to abrupt deletion without it?
|
|
var target_vol = set_atten(body, rustle_sounds, true)
|
|
var fade_time = FADE_IN_OUT
|
|
while fade_time > 0.0:
|
|
rustle_sounds.global_position = body.global_position
|
|
rustle_sounds.volume_db = lerp(-80.0, target_vol, (FADE_IN_OUT-fade_time)/FADE_IN_OUT)
|
|
await get_tree().process_frame
|
|
fade_time -= get_process_delta_time()
|
|
|
|
if overlaps_body(body):
|
|
# this check sometimes fails because godot doesn't guarantee up to date results
|
|
# so sometimes you'll get the bug where the foliage noise keeps on playing after you get out of foliage
|
|
# i'm too tired to fix this, this script is bloated enough as it is
|
|
# interestingly enough i've run into this bug in other AAA games as well
|
|
collider_audio_pair.append({"collider": body, "audio": rustle_sounds})
|
|
else:
|
|
var from_vol = set_atten(body, rustle_sounds, true)
|
|
var fade_time2 = FADE_IN_OUT
|
|
while fade_time2 > 0.0:
|
|
rustle_sounds.global_position = body.global_position
|
|
rustle_sounds.volume_db = lerp(from_vol, -80.0, (FADE_IN_OUT-fade_time2)/FADE_IN_OUT)
|
|
await get_tree().process_frame
|
|
fade_time2 -= get_process_delta_time()
|
|
rustle_sounds.queue_free()
|
|
|
|
func _on_body_exited(body):
|
|
for pair in collider_audio_pair:
|
|
if pair["collider"] == body:
|
|
var temp_audio = pair["audio"]
|
|
var temp_obj = pair["collider"]
|
|
collider_audio_pair.erase(pair)
|
|
|
|
var from_vol = set_atten(body, rustle_sounds, true)
|
|
var fade_time = FADE_IN_OUT
|
|
while fade_time > 0.0:
|
|
temp_audio.global_position = temp_obj.global_position
|
|
temp_audio.volume_db = lerp(from_vol, -80.0, (FADE_IN_OUT-fade_time)/FADE_IN_OUT)
|
|
await get_tree().process_frame
|
|
fade_time -= get_process_delta_time()
|
|
|
|
temp_audio.queue_free()
|
|
break
|
|
|
|
func ease_out_circ(lerp: float) -> float:
|
|
return sqrt(1.0 - pow(lerp - 1.0, 2.0))
|