MIF_E31230535/panzerboss.gd

207 lines
7.0 KiB
GDScript

extends Node2D
signal mati # 👈 Sinyal agar stage bisa mendengar kematian TANK!
# ==============================================================================
# 🎛️ SETELAN AUDIO MANUAL PANZER (UBAH DI SINI)
# ==============================================================================
# Nilai dalam desibel (dB). Shiro set ke 10.0 dB agar suaranya lantang dan keras!
@export var VOLUME_TEMBAKAN: float = 10.0
# ==============================================================================
# --- ⚙️ PENGATURAN ROTASI RODA ---
@export var kecepatan_rotasi_roda: float = 5.0
# --- 🔫 PENGATURAN TEMBAKAN PANZER ---
@export var peluru_scene: PackedScene = preload("res://pelurumusuhfase_2.tscn")
@export var jeda_tembak: float = 3.0 # Jeda antar tembakan (Fase Diam)
@export var kecepatan_putar_laras: float = 2.0 # Semakin cepat laras berputar
@export var damage_tembakan: float = 30.0 # DAMAGE YANG DILEMPAR PANZER KE PELURUNYA
# --- 📐 BATAS ROTASI LARAS ---
@export_group("Batas Rotasi Meriam")
@export var batas_mendongak_keatas: float = 45.0 # Maksimal mendongak 45 derajat ke atas
@export var batas_menunduk_kebawah: float = 10.0 # Maksimal menunduk 10 derajat ke bawah
# --- 🖼️ TEXTURE UNTUK FASE KERUSAKAN TANK ---
@export_group("Visual Kerusakan Bodi")
@export var tekstur_body_hp_100: Texture2D # Gambar tank saat HP 100 kebawah
@export var tekstur_body_hp_50: Texture2D # Gambar tank saat HP 50 kebawah
@export var tekstur_body_hancur_0: Texture2D # Gambar tank jadi bangkai rongsokan saat HP 0
# --- 🛡️ PENGATURAN NYAWA PANZER ---
@export var health = 200
var is_destroyed = false
# 🎵 AMBIL REFERENSI NODE AUDIO UNTUK EFEK SUARA TEMBAKAN
@onready var audio_tembakan = $AudioStreamPlayer
# Daftar untuk menyimpan referensi ke-11 Sprite2D ban secara otomatis
var daftar_ban: Array[Sprite2D] = []
# Referensi Node Laras, Titik Tembak, dan Bodi Tank
var node_laras: Sprite2D = null
var titik_tembak: Marker2D = null
var node_body_sprite: Sprite2D = null
# Variabel pembantu AI & Pergerakan
var posisi_terakhir_x: float = 0.0
var player_target: Node2D = null
# --- 🧭 VARIABEL KONTROL ROTASI ---
var sudut_target_laras: float = 0.0
var sedang_membidik: bool = false
func _ready() -> void:
print("🪖 Final Boss: Tank Panzer (HP 200) bersiap!")
posisi_terakhir_x = global_position.x
player_target = get_tree().current_scene.get_node_or_null("Player")
var node_static_body = get_node_or_null("StaticBody2D")
if node_static_body:
node_body_sprite = node_static_body.get_node_or_null("body")
node_laras = node_static_body.get_node_or_null("laras")
if node_laras:
titik_tembak = node_laras.get_node_or_null("TitikTembak")
sudut_target_laras = node_laras.rotation
for i in range(1, 12):
var nama_ban = "ban" + str(i)
var node_ban = node_static_body.get_node_or_null(nama_ban)
if node_ban and node_ban is Sprite2D:
daftar_ban.append(node_ban)
print("⚙️ Berhasil mendaftarkan ", daftar_ban.size(), " roda Panzer.")
mulai_siklus_tembak_panzer()
else:
print("❌ Eror: Node induk 'StaticBody2D' tidak ditemukan!")
func _physics_process(delta: float) -> void:
if is_destroyed: return
var pergerakan_x = global_position.x - posisi_terakhir_x
if pergerakan_x < -0.01:
putar_semua_roda(-kecepatan_rotasi_roda * delta)
elif pergerakan_x > 0.01:
putar_semua_roda(kecepatan_rotasi_roda * delta)
posisi_terakhir_x = global_position.x
if node_laras:
if sedang_membidik and player_target:
var arah_ke_player = node_laras.global_position.direction_to(player_target.global_position)
var sudut_mentah = arah_ke_player.angle()
var sudut_derajat = rad_to_deg(sudut_mentah)
var selisih_sudut = sudut_derajat - 180.0
selisih_sudut = fposmod(selisih_sudut + 180.0, 360.0) - 180.0
selisih_sudut = clamp(selisih_sudut, -batas_menunduk_kebawah, batas_mendongak_keatas)
sudut_target_laras = deg_to_rad(selisih_sudut)
else:
sudut_target_laras = 0.0
node_laras.rotation = rotate_toward(node_laras.rotation, sudut_target_laras, kecepatan_putar_laras * delta)
func putar_semua_roda(jumlah_rotasi: float) -> void:
for ban in daftar_ban:
if is_instance_valid(ban):
ban.rotation += jumlah_rotasi
func mulai_siklus_tembak_panzer() -> void:
while true:
if is_destroyed: break
sedang_membidik = false
await get_tree().create_timer(jeda_tembak).timeout
if is_destroyed: break
if not player_target or ("is_hiding" in player_target and player_target.is_hiding):
continue
sedang_membidik = true
await get_tree().create_timer(1.5).timeout
if is_destroyed: break
eksekusi_tembakan_meriam()
await get_tree().create_timer(0.5).timeout
func eksekusi_tembakan_meriam() -> void:
if not peluru_scene or not titik_tembak or not node_laras or is_destroyed: return
print("💥 BOOM! Tembakan Panzer meletus! Mengirim damage: ", damage_tembakan)
# 🎵 MAINKAN AUDIO TEMBAKAN & ATUR VOLUMENYA AGAR LEBIH KERAS
if audio_tembakan:
audio_tembakan.volume_db = VOLUME_TEMBAKAN
audio_tembakan.play()
var p = peluru_scene.instantiate()
p.global_position = titik_tembak.global_position
if "damage" in p:
p.damage = damage_tembakan
var arah_tembakan = Vector2.LEFT.rotated(node_laras.global_rotation)
if "direction" in p:
p.direction = arah_tembakan
p.rotation = arah_tembakan.angle()
get_tree().current_scene.add_child(p)
# --- 🛡️ LOGIKA MENERIMA DAMAGE ---
func kurangi_nyawa(jumlah):
if is_destroyed: return
health -= jumlah
print("🛡️ Tank Panzer Terhantam! HP Panzer: ", health)
if node_body_sprite:
if health <= 0:
if tekstur_body_hancur_0:
node_body_sprite.texture = tekstur_body_hancur_0
elif health <= 50:
if tekstur_body_hp_50:
node_body_sprite.texture = tekstur_body_hp_50
print("🚨 CRITICAL! Gambar berubah ke sprite HP 50 kebawah.")
elif health <= 100:
if tekstur_body_hp_100:
node_body_sprite.texture = tekstur_body_hp_100
print("⚠️ WARNING! Gambar berubah ke sprite HP 100 kebawah.")
if health <= 0:
hancurkan_tank()
# --- 💀 LOGIKA HANCUR ---
func hancurkan_tank():
is_destroyed = true
sedang_membidik = false
print("💀 TANK PANZER BERHASIL DIHANCURKAN! STAGE 3 CLEAR!")
# Pancarkan sinyal ke Stage (Tanpa memicu audio apa pun)
mati.emit()
# Panggil rem darurat di script Stage 3
var node_stage = get_parent()
if node_stage and node_stage.has_method("hentikan_pergerakan_panzer"):
node_stage.hentikan_pergerakan_panzer()
# Atur posisi dan skala sprite bangkai secara presisi
if node_body_sprite:
node_body_sprite.position = Vector2(575.5, 269.0)
node_body_sprite.scale = Vector2(2.135, 2.106)
print("📐 Posisi & Skala bangkai Panzer berhasil disesuaikan!")
# Hapus laras meriam beserta node anaknya
if node_laras:
node_laras.queue_free()
print("🗑️ Node Laras dibersihkan.")
# Matikan bentuk tabrakan agar player bisa lewat bebas
var body = get_node_or_null("StaticBody2D")
if body:
for child in body.get_children():
if child is CollisionPolygon2D or child is CollisionShape2D:
child.set_deferred("disabled", true)
print("🛡️ Collision bodi tank dinonaktifkan.")