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()])