vrp-gruppe-sechs/disco-escape-roomv-5/strobo_effekt.gd

139 lines
4.3 KiB
GDScript

extends Node3D
class_name StrobeEffect
## Audio-reaktiver Stroboskop-Effekt für Light3D-Nodes
## Version mit AudioManager Singleton (OPTIMIERT)
@export_group("Target Lights")
@export var target_lights: Array[Light3D] = []
@export_group("Audio Settings")
@export var audio_player: AudioStreamPlayer3D
@export var audio_reactive: bool = true
@export_enum("Bass", "Mitten", "Höhen", "Alle") var frequency_range: int = 0
@export_range(0.1, 5.0) var audio_sensitivity: float = 1.5
@export_range(0.0, 1.0) var audio_smoothing: float = 0.2
@export_group("Strobe Settings")
@export var strobe_enabled: bool = true
@export_range(1.0, 30.0) var strobe_speed: float = 12.0
@export_range(0.0, 100.0) var strobe_energy: float = 25.0
@export_range(0.0, 1.0) var strobe_threshold: float = 0.3
@export var async_strobes: bool = true
# Interne Variablen
var current_audio_magnitude: float = 0.0
var target_audio_magnitude: float = 0.0
var strobe_timer: float = 0.0
var strobe_phase_offsets: Array[float] = []
var original_energies: Array[float] = []
func _ready():
randomize()
_initialize_lights()
# Setup Audio mit AudioManager Singleton
if audio_reactive and audio_player:
if AudioManager.setup(audio_player):
print("StrobeEffect '%s': Nutzt AudioManager für Audio-Reaktivität" % name)
else:
push_error("StrobeEffect '%s': AudioManager-Setup fehlgeschlagen!" % name)
audio_reactive = false
func _process(delta):
# Hole Audio-Daten vom Manager (bereits berechnet!)
if audio_reactive and AudioManager.is_playing():
_update_audio_reactivity(delta)
if strobe_enabled:
_apply_strobe_effect(delta)
func _initialize_lights():
# Speichere Original-Energiewerte und erstelle Phasen-Offsets
for light in target_lights:
if is_instance_valid(light):
original_energies.append(light.light_energy)
if async_strobes:
strobe_phase_offsets.append(randf_range(0.0, TAU))
else:
strobe_phase_offsets.append(0.0)
print("StrobeEffect '%s': %d Lichter initialisiert" % [name, target_lights.size()])
## OPTIMIERT: Nutzt vorberechnete Werte vom AudioManager
func _update_audio_reactivity(_delta):
# Hole Magnitude vom Manager (bereits gefiltert nach frequency_range)
var raw_magnitude = AudioManager.get_magnitude(frequency_range)
# Anwenden von Sensitivity und Smoothing
target_audio_magnitude = clamp(raw_magnitude * audio_sensitivity, 0.0, 1.0)
current_audio_magnitude = lerp(current_audio_magnitude, target_audio_magnitude, 1.0 - audio_smoothing)
func _apply_strobe_effect(delta):
strobe_timer += delta * strobe_speed
var magnitude_normalized = current_audio_magnitude
for i in range(target_lights.size()):
if i >= target_lights.size():
break
var light = target_lights[i]
if not is_instance_valid(light):
continue
var phase = strobe_timer + strobe_phase_offsets[i]
var light_on = sin(phase) > 0.0 and magnitude_normalized > strobe_threshold
# Strobe-Effekt anwenden
if light_on:
light.light_energy = strobe_energy
light.visible = true
else:
light.light_energy = 0.0
light.visible = false
# === Public Methods ===
func add_light(light: Light3D):
"""Fügt ein Licht zum Strobe-Effekt hinzu"""
if light and not light in target_lights:
target_lights.append(light)
original_energies.append(light.light_energy)
if async_strobes:
strobe_phase_offsets.append(randf_range(0.0, TAU))
else:
strobe_phase_offsets.append(0.0)
func remove_light(light: Light3D):
"""Entfernt ein Licht vom Strobe-Effekt"""
var idx = target_lights.find(light)
if idx != -1:
target_lights.remove_at(idx)
original_energies.remove_at(idx)
strobe_phase_offsets.remove_at(idx)
func enable_strobe(enable: bool):
"""Aktiviert/Deaktiviert den Strobe-Effekt"""
strobe_enabled = enable
if not enable:
# Stelle Original-Energien wieder her
for i in range(target_lights.size()):
if is_instance_valid(target_lights[i]) and i < original_energies.size():
target_lights[i].light_energy = original_energies[i]
target_lights[i].visible = true
func set_all_lights_in_parent():
"""Automatisch alle Light3D-Kinder des Parent-Nodes hinzufügen"""
if not get_parent():
return
target_lights.clear()
original_energies.clear()
strobe_phase_offsets.clear()
for child in get_parent().get_children():
if child is Light3D:
add_light(child)
print("StrobeEffect '%s': %d Lichter automatisch gefunden" % [name, target_lights.size()])