extends Node2D @onready var crosshair = $Crosshair # 🎬 Ambil referensi ke AnimationPlayer transisi @onready var anim_player = $TransitionLayer/fade_to_black # ============================================================================== # 🎛️ SETELAN AUDIO MANUAL MINIGAME SNIPER (UBAH DI SINI) # ============================================================================== # Nilai volume dasar dalam desibel (dB) untuk musik sniper var VOLUME_DASAR_BGM: float = -5.0 # Durasi efek transisi suara masuk dan keluar (dalam detik) var DURASI_FADE_IN: float = 3.0 var DURASI_FADE_OUT: float = 1.5 # ============================================================================== # 🎵 AMBIL REFERENSI NODE AUDIO TUNGGAL (Sesuai nama bawaan di scene) @onready var audio_player = $AudioStreamPlayer # 🔊 BARU: REFERENSI NODE AUDIO KEDUA UNTUK SFX TEMBAKAN SNIPER @onready var sfx_tembak = $AudioStreamPlayer2 # --- REFERENSI LANGSUNG KE KEDUA TENTARA --- @onready var soldier_1 = $Soldier @onready var soldier_2 = $Soldier2 var is_finishing = false # --- VARIABEL UNTUK COUNTER --- var total_target = 0 var target_tereliminasi = 0 # --- STRUKTUR DATA PATROLI UNTUK MULTI-MUSUH --- enum StatePatroli { JALAN_KANAN, DIAM_KANAN, JALAN_KIRI, DIAM_KIRI } # Kita buatkan konfigurasi terpisah menggunakan Dictionary agar gerakannya tidak seragam/kaku var data_patroli = {} @export var kecepatan_patroli = 100.0 @export var durasi_diam = 2.0 @export var jarak_patroli = 150.0 # Jarak bolak-balik dari titik awal masing-masing # --- 🎯 VARIABEL SENSITIVITAS SLIDE ANDROID --- @export var sensitivitas_sentuhan : float = 1.2 func _ready(): # 🎬 1. JALANKAN ANIMASI FADE IN SAAT SCENE SNIPER BARU DIMUAT if anim_player and anim_player.has_animation("fadein"): anim_player.play("fadein") print("🎬 Sniper Stage Dimulai: Memutar animasi fadein...") # 2. Inisialisasi posisi awal dan state untuk masing-masing soldier inisialisasi_musuh(soldier_1) inisialisasi_musuh(soldier_2) # 3. Hitung berapa banyak musuh yang ada di awal permainan total_target = get_tree().get_nodes_in_group("musuh").size() print("Misi Sniper Dimulai! Total target: ", total_target) # 🎵 SISTEM FADE IN OTOMATIS AUDIO TUNGGAL if audio_player: if audio_player.stream and audio_player.stream is AudioStreamOggVorbis: audio_player.stream.loop = true audio_player.volume_db = -80.0 # Mulai dari senyap total audio_player.play() var tween = create_tween() tween.tween_property(audio_player, "volume_db", VOLUME_DASAR_BGM, DURASI_FADE_IN)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_OUT) print("🎵 Musik Sniper mulai berputar dengan efek Fade-In ke ", VOLUME_DASAR_BGM, " dB!") func inisialisasi_musuh(node_musuh): if is_instance_valid(node_musuh): data_patroli[node_musuh] = { "titik_awal_x": node_musuh.global_position.x, "status_sekarang": StatePatroli.JALAN_KANAN, "timer_patroli": 0.0 } func _physics_process(delta): # Jalankan pergerakan untuk semua musuh yang terdaftar jika mereka masih valid for musuh in data_patroli.keys(): if is_instance_valid(musuh) and not musuh.is_dead and not musuh.is_chasing: logika_kontrol_patroli(musuh, delta) func _input(event): if is_finishing: return # 📲 LOGIKA MULTI-PLATFORM UNTUK ANDROID (SLIDE LAYAR) if event is InputEventScreenDrag: crosshair.global_position += event.relative * sensitivitas_sentuhan # 💻 LOGIKA MULTI-PLATFORM UNTUK PC (IKUTI MOUSE) elif event is InputEventMouseMotion and OS.get_name() != "Android": crosshair.global_position = get_global_mouse_position() # 💥 LOGIKA MENEMBAK (Mendukung Klik Kiri PC ATAU Tombol UI Android) if event.is_action_pressed("click_kiri"): tembak() # --- MESIN PENGGERAK OTOMATIS MULTI-MUSUH --- func logika_kontrol_patroli(musuh, delta): var data = data_patroli[musuh] match data["status_sekarang"]: StatePatroli.JALAN_KANAN: musuh.velocity.x = kecepatan_patroli if musuh.global_position.x >= (data["titik_awal_x"] + jarak_patroli): musuh.velocity.x = 0 data["status_sekarang"] = StatePatroli.DIAM_KANAN data["timer_patroli"] = 0.0 StatePatroli.DIAM_KANAN: data["timer_patroli"] += delta if data["timer_patroli"] >= durasi_diam: data["status_sekarang"] = StatePatroli.JALAN_KIRI StatePatroli.JALAN_KIRI: musuh.velocity.x = -kecepatan_patroli if musuh.global_position.x <= (data["titik_awal_x"] - jarak_patroli): musuh.velocity.x = 0 data["status_sekarang"] = StatePatroli.DIAM_KIRI data["timer_patroli"] = 0.0 StatePatroli.DIAM_KIRI: data["timer_patroli"] += delta if data["timer_patroli"] >= durasi_diam: data["status_sekarang"] = StatePatroli.JALAN_KANAN func tembak(): print("DOR!") # 🔊 BARU: MAINKAN SFX TEMBAKAN SETIAP KALI TOMBOL INTERAKSI DILEPAS if sfx_tembak: sfx_tembak.play() print("🔊 SFX: Suara tembakan sniper senapan rifle bergelegar!") if has_node("Camera2D"): $Camera2D.apply_shake(10.0) var target = crosshair.get_target_terbidik() if target and target.has_method("stealth_assassination"): target.stealth_assassination() target_tereliminasi += 1 print("Target kena! Progress: ", target_tereliminasi, "/", total_target) cek_progres_misi() func cek_progres_misi(): if target_tereliminasi >= total_target and not is_finishing: is_finishing = true mulai_transisi_kembali() func mulai_transisi_kembali(): print("Semua target tumbang! Menunggu jeda sejenak...") await get_tree().create_timer(1.5).timeout # 🎵 TURUNKAN VOLUME AUDIO PERLAHAN (FADE-OUT) SEBELUM PINDAH SCENE if audio_player and audio_player.is_playing(): var tween_out = create_tween() tween_out.tween_property(audio_player, "volume_db", -80.0, DURASI_FADE_OUT)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_IN) print("🎵 Menurunkan volume musik sniper secara sinematik (Fade-Out)...") if anim_player and anim_player.has_animation("fadeout"): anim_player.play("fadeout") await anim_player.animation_finished # 🎵 Matikan audio secara total demi menghemat memori setelah layar hitam if audio_player: audio_player.stop() print("🚀 Kembali ke perjalanan utama...") get_tree().change_scene_to_file("res://stage1_2.tscn")