extends Node2D # --- 🛠️ PRELOAD CETAKAN TUTORIAL UTAMA --- const TUTORIAL_SCENE = preload("res://tutorial.tscn") # ============================================================================== # 🎛️ SETELAN AUDIO MANUAL STAGE 0 (UBAH DI SINI) # ============================================================================== var VOLUME_DASAR_BGM: float = 10.0 var VOLUME_DASAR_BGM_2: float = -5.0 var DURASI_FADE_IN: float = 3.0 var DURASI_FADE_OUT: float = 1.5 # ============================================================================== @onready var bgm_player = $AudioStreamPlayer @onready var bgm_player_2 = $AudioStreamPlayer2 var game_selesai = false @onready var player = $Player @onready var folder_npc = $NPC var template_npc: Dictionary = {} var kecepatan_npc: float = 120.0 var jarak_jalan_npc: float = 2100.0 func _ready() -> void: # 🎬 Memutar animasi fadein saat stage pertama kali dibuka $TransitionLayer/fade_to_black.play("fadein") player.SPEED = 300 # 🎵 SISTEM FADE IN AUDIO OTOMATIS (AUDIO 1) if bgm_player: if bgm_player.stream and bgm_player.stream is AudioStreamOggVorbis: bgm_player.stream.loop = true bgm_player.volume_db = -80.0 bgm_player.play() var tween_fadein = create_tween() tween_fadein.tween_property(bgm_player, "volume_db", VOLUME_DASAR_BGM, DURASI_FADE_IN)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_OUT) print("🎵 Musik 1 di Inspector berhasil diputar dengan efek Fade-In!") # 🎵 SISTEM FADE IN AUDIO OTOMATIS (AUDIO 2) if bgm_player_2: if bgm_player_2.stream and bgm_player_2.stream is AudioStreamOggVorbis: bgm_player_2.stream.loop = true bgm_player_2.volume_db = -80.0 bgm_player_2.play() var tween_fadein2 = create_tween() tween_fadein2.tween_property(bgm_player_2, "volume_db", VOLUME_DASAR_BGM_2, DURASI_FADE_IN)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_OUT) print("🎵 Musik 2 di Inspector berhasil diputar dengan efek Fade-In bersamaan!") # 🛠️ AMBIL DAN SEMBUNYIKAN TEMPLATE NPC ASLI for i in range(1, 7): var nama_node = "npc" + str(i) var node_npc = folder_npc.get_node_or_null(nama_node) if node_npc: template_npc[i] = node_npc node_npc.visible = false else: print("⚠️ Peringatan: Node ", nama_node, " tidak ditemukan di dalam folder NPC!") # 🚀 MEMULAI DUA LOOP PARALEL (GANJIL & GENAP) loop_spawner_ganjil() loop_spawner_genap() # 🛠️ BARU: PICU TUTORIAL GERAKAN SAAT AWAL MULAI STAGE pemicu_tutorial_awal() # --- 🛠️ FUNGSI UNTUK MEMUNCULKAN TUTORIAL GERAKAN DI AWAL --- func pemicu_tutorial_awal() -> void: var tutorial_instance = TUTORIAL_SCENE.instantiate() # Memasukkan teks panduan gerakan dasar ke dalam cetakan tutorial tutorial_instance.teks_panduan = "Tutorial:\nGunakan tombol Kiri dan Kanan untuk menggerakkan Karakter.\nGunakan juga tombol 'Jump' untuk membuat Karakter melompat." # Munculkan ke layar utama stage (Otomatis mem-pause game lewat Engine.time_scale) get_tree().current_scene.add_child(tutorial_instance) print("💡 Tutorial Gerakan Awal berhasil dimunculkan.") # --- 🏃‍♂️ LOOP 1: SPAWN GANJIL (TIAP 6 DETIK) --- func loop_spawner_ganjil(): while not game_selesai: spawn_grup_npc([1, 3, 5]) await get_tree().create_timer(6.0).timeout # --- 🏃‍♂️ LOOP 2: SPAWN GENAP WITH OFFSET (TIAP 6 DETIK, DELAY 3 DETIK DI AWAL) --- func loop_spawner_genap(): await get_tree().create_timer(3.0).timeout while not game_selesai: spawn_grup_npc([2, 4, 6]) await get_tree().create_timer(6.0).timeout # --- 🛠️ FUNGSI UNTUK MENDUPLIKAT & MENGGERAKKAN NPC --- func spawn_grup_npc(daftar_angka: Array): for angka in daftar_angka: if not template_npc.has(angka) or game_selesai: continue var npc_clone = template_npc[angka].duplicate() folder_npc.add_child(npc_clone) npc_clone.visible = true npc_clone.modulate.a = 0.0 eksekusi_animasi_dan_gerak_npc(npc_clone, angka) func eksekusi_animasi_dan_gerak_npc(npc: Node2D, angka: int): var anim_player = npc.get_node_or_null("animasi") if anim_player and anim_player.has_animation("idle"): anim_player.play("idle") var arah = 1.0 if angka == 3 or angka == 4: arah = -1.0 npc.scale.x = -abs(npc.scale.x) else: arah = 1.0 npc.scale.x = abs(npc.scale.x) var durasi = jarak_jalan_npc / kecepatan_npc var posisi_tujuan = npc.global_position + Vector2(jarak_jalan_npc * arah, 0) var tween_gerak = create_tween() tween_gerak.tween_property(npc, "global_position:x", posisi_tujuan.x, durasi).set_trans(Tween.TRANS_LINEAR) var tween_fade = create_tween() tween_fade.tween_property(npc, "modulate:a", 1.0, 0.5) var waktu_tunggu_fadeout = max(0.1, durasi - 1.0) tween_fade.tween_interval(waktu_tunggu_fadeout) tween_fade.tween_property(npc, "modulate:a", 0.0, 0.5) tween_gerak.finished.connect(func(): npc.queue_free()) # --- 🏁 GARIS FINISH STAGE 0 --- func _on_finish_line_body_entered(body: Node2D) -> void: print("Seseorang menabrak garis finish!") if body is CharacterBody2D and not game_selesai: print("Robot terdeteksi! Jalankan animasi...") game_selesai = true if Global.stage_terbuka == 0: Global.stage_terbuka = 1 print("💾 Progress Diupdate: Stage 0 Selesai -> Stage 1 Terbuka!") # 🎵 EFEK FADE OUT AUDIO 1 SAAT MENABRAK FINISH LINE if bgm_player and bgm_player.is_playing(): print("🎵 Menurunkan volume musik Stage 0 (Audio 1) perlahan (Fade-Out)...") var tween_fadeout = create_tween() tween_fadeout.tween_property(bgm_player, "volume_db", -80.0, DURASI_FADE_OUT)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_IN) # 🎵 EFEK FADE OUT AUDIO 2 SAAT MENABRAK FINISH LINE if bgm_player_2 and bgm_player_2.is_playing(): print("🎵 Menurunkan volume musik Stage 0 (Audio 2) perlahan (Fade-Out)...") var tween_fadeout2 = create_tween() tween_fadeout2.tween_property(bgm_player_2, "volume_db", -80.0, DURASI_FADE_OUT)\ .set_trans(Tween.TRANS_QUAD)\ .set_ease(Tween.EASE_IN) $TransitionLayer/fade_to_black.play("fadeout") await get_tree().create_timer(1.5).timeout # 🎵 Matikan kedua audio sepenuhnya setelah layar hitam total demi memori if bgm_player: bgm_player.stop() if bgm_player_2: bgm_player_2.stop() get_tree().change_scene_to_file("res://cutstage0_2.tscn")