MIF_E31230535/player.gd

323 lines
9.2 KiB
GDScript

@tool
class_name Player
extends CharacterBody2D
# --- VARIABEL ---
# 🎛️ SETELAN AUDIO MANUAL TEMBAKAN
var VOLUME_TEMBAKAN_MANUAL: float = -8.0
@onready var sfx_tembakan = $AudioStreamPlayer
@export var bisa_menunduk : bool = false
@export var hanya_boleh_menunduk : bool = false
@export var peluru_scene : PackedScene # Drag file pelururifle.tscn ke sini di Inspector
# --- VARIABEL UNTUK SKIN CUSTOM ---
@export var kostum_badan_custom: Texture2D
@export var kostum_tangan_kanan_custom: Texture2D
@export var kostum_tangan_kiri_custom: Texture2D
@export var kostum_kepala_custom: Texture2D
# Tombol utama di Inspector
@export var is_pegang_senjata : bool = false:
set(value):
is_pegang_senjata = value
if is_node_ready():
proses_senjata(value)
update_animation_state()
signal hp_berubah(hp_sekarang)
# --- VARIABEL POWER UP TRIPLE SHOT ---
var is_triple_shot : bool = false
var is_menunduk = false
var sedang_di_tangga = false
var health = 100
var is_dead = false
@export var SPEED : float = 600
const JUMP_VELOCITY = -600.0
const CLIMB_SPEED = 400.0
var is_hiding = false
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
@onready var visual = $Visual
@onready var anim_player = $AnimasiIdle
@onready var collision = $CollisionShape2D
@onready var tangan_kanan = $Visual/tangankanan
@onready var tangan_kiri = $Visual/tangankiri
@onready var senjata = $Visual/senjata
@onready var muzzle = $Visual/senjata/muzzle # Titik peluru keluar
# 🔪 FIX 1: AMBIL REFERENSI SPRITE PISAU (Letakkan di bawah muzzle)
@onready var sprite_pisau = $Visual/pisau
func terima_damage(jumlah):
if is_dead: return
health -= jumlah
health = clamp(health, 0, 100)
# "Terpancar" atau kirim signal setiap kali HP berubah
emit_signal("hp_berubah", health)
print("HP Player: ", health)
if health <= 0:
mati()
func mati():
if is_dead: return
is_dead = true
print("Robot Biru Hancur! Mengalihkan ke Layar Game Over...")
set_physics_process(false)
# Catat lokasi terakhir
Globaltimer.scene_terakhir_player = get_tree().current_scene.scene_file_path
call_deferred("pindah_ke_gameover")
func pindah_ke_gameover():
get_tree().change_scene_to_file("res://gameover.tscn")
func _ready():
if not Engine.is_editor_hint():
proses_senjata(is_pegang_senjata)
# 🥷 Pastikan pisau tersembunyi di awal permainan
if sprite_pisau:
sprite_pisau.visible = false
if kostum_badan_custom:
$Visual/badan.texture = kostum_badan_custom
if kostum_tangan_kanan_custom:
$Visual/tangankanan.texture = kostum_tangan_kanan_custom
if kostum_tangan_kiri_custom:
$Visual/tangankiri.texture = kostum_tangan_kiri_custom
$Visual/tangankiri.offset.x = -23
if kostum_kepala_custom:
$Visual/kepala.texture = kostum_kepala_custom
func _physics_process(delta):
if Engine.is_editor_hint(): return
if is_hiding:
velocity = Vector2.ZERO
return
# LOGIKA TOGGLE SENJATA (Tab)
if Input.is_action_just_pressed("ui_focus_next"):
is_pegang_senjata = !is_pegang_senjata
# LOGIKA BIDIK & TEMBAK (Hanya saat pegang senjata)
if is_pegang_senjata:
var crosshair = get_tree().current_scene.find_child("Crosshair", true, false)
if crosshair and crosshair.visible:
senjata.look_at(get_global_mouse_position())
senjata.flip_v = (get_global_mouse_position().x < global_position.x)
else:
senjata.rotation_degrees = 0
senjata.flip_v = false
# SINKRON: Menggunakan "click_kiri" sesuai setup Input Map kamu
if Input.is_action_just_pressed("click_kiri"):
tembak()
if hanya_boleh_menunduk:
velocity.x = 0
if bisa_menunduk and Input.is_action_just_pressed("gerak_bawah"):
proses_menunduk(!is_menunduk)
if not is_on_floor():
velocity.y += gravity * delta
move_and_slide()
update_animation_state()
return
# 1. Gravitasi & Tangga
if not is_on_floor() and not sedang_di_tangga:
velocity.y += gravity * delta
if sedang_di_tangga:
if Input.is_action_pressed("gerak_atas"): velocity.y = -CLIMB_SPEED
elif Input.is_action_pressed("gerak_bawah"): velocity.y = CLIMB_SPEED
else: velocity.y = 0
# 2. Lompat & Menunduk
if Input.is_action_just_pressed("lompat") and is_on_floor():
velocity.y = JUMP_VELOCITY
if bisa_menunduk and is_on_floor() and not sedang_di_tangga:
if Input.is_action_just_pressed("gerak_bawah"):
proses_menunduk(!is_menunduk)
# 3. Gerak Kiri-Kanan
var direction = Input.get_axis("gerak_kiri", "gerak_kanan")
if direction:
var current_speed = SPEED * 0.5 if is_menunduk else SPEED
velocity.x = direction * current_speed
visual.scale.x = direction
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
update_animation_state()
func tembak():
if !peluru_scene: return
if is_menunduk:
print("❌ Player tidak bisa menembak sambil menunduk/berjongkok!")
return
if is_triple_shot:
for i in range(3):
if is_dead: break
_eksekusi_instansiasi_peluru()
await get_tree().create_timer(0.1).timeout
else:
_eksekusi_instansiasi_peluru()
func _eksekusi_instansiasi_peluru():
var p = peluru_scene.instantiate()
var arah_tembakan = Vector2.ZERO
var crosshair = get_tree().current_scene.find_child("Crosshair", true, false)
if crosshair and crosshair.visible:
arah_tembakan = (get_global_mouse_position() - muzzle.global_position).normalized()
else:
arah_tembakan = Vector2(visual.scale.x, 0)
p.global_position = muzzle.global_position
p.direction = arah_tembakan
p.rotation = arah_tembakan.angle()
get_tree().current_scene.add_child(p)
if sfx_tembakan:
sfx_tembakan.stop()
sfx_tembakan.volume_db = VOLUME_TEMBAKAN_MANUAL
sfx_tembakan.play()
func update_animation_state():
if Engine.is_editor_hint(): return
# 🚷 FIX UTAMA: Pengaman ini HARUS ditaruh paling atas sebelum pengecekan menunduk/tangga!
if anim_player and anim_player.current_animation == "tusuk":
return
if is_menunduk or sedang_di_tangga: return
var anim_suffix = "_weapon" if is_pegang_senjata else ""
if velocity.x != 0 and is_on_floor():
var anim_walk = "walk" + anim_suffix
if anim_player.has_animation(anim_walk):
anim_player.play(anim_walk)
elif is_on_floor():
var anim_idle = "idle" + anim_suffix
if anim_player.has_animation(anim_idle):
# Reset posisi visual
for child in visual.get_children():
if child is Sprite2D:
child.position = Vector2.ZERO
if not (is_pegang_senjata and (child == tangan_kanan or child == tangan_kiri)):
child.rotation_degrees = 0
anim_player.play(anim_idle)
if is_pegang_senjata:
tangan_kanan.position = Vector2(-26, 4)
tangan_kanan.rotation_degrees = -68
tangan_kiri.position = Vector2(17, 4)
tangan_kiri.rotation_degrees = -80
senjata.position = Vector2(46, 12)
else:
tangan_kanan.position = Vector2.ZERO
tangan_kanan.rotation_degrees = 0
tangan_kiri.position = Vector2.ZERO
tangan_kiri.rotation_degrees = 0
func proses_senjata(status: bool):
if !tangan_kanan or !tangan_kiri or !senjata: return
senjata.visible = status
if status:
tangan_kanan.position = Vector2(-26, 4)
tangan_kanan.rotation_degrees = -68
tangan_kiri.position = Vector2(17, 4)
tangan_kiri.rotation_degrees = -80
senjata.position = Vector2(46, 12)
senjata.rotation_degrees = 0
else:
tangan_kanan.position = Vector2.ZERO
tangan_kanan.rotation_degrees = 0
tangan_kiri.position = Vector2.ZERO
tangan_kiri.rotation_degrees = 0
senjata.position = Vector2.ZERO
senjata.rotation_degrees = 0
func proses_menunduk(status: bool):
is_menunduk = status
if status:
visual.position.y = 15
collision.scale.y = 0.5
anim_player.stop()
else:
visual.position.y = 0
collision.scale.y = 1.0
func reset_posisi_visual():
if is_pegang_senjata: return
for child in visual.get_children():
if child is Sprite2D:
child.position = Vector2.ZERO
func set_di_tangga(status: bool):
sedang_di_tangga = status
if status and is_menunduk: proses_menunduk(false)
func _on_speed_slider_value_changed(value: float): SPEED = value
func eksekusi_kematian_player():
print("Player mati!")
set_physics_process(false)
Globaltimer.scene_terakhir_player = get_tree().current_scene.scene_file_path
get_tree().change_scene_to_file("res://gameover.tscn")
func tambah_hp(jumlah):
if is_dead: return
health += jumlah
health = clamp(health, 0, 100)
emit_signal("hp_berubah", health)
print("💊 Darah berhasil dipulihkan! HP Player Sekarang: ", health)
func aktifkan_triple_shot(durasi: float = 15.0):
if is_dead: return
is_triple_shot = true
print("🔥 Power-Up Aktif: Tembakan 3 Peluru Beruntun!")
await get_tree().create_timer(durasi).timeout
is_triple_shot = false
print("🔋 Durasi Triple Shot habis. Senjata kembali ke mode normal.")
# --- 🥷 FUNGSI UTAMA STEALTH KILL PLAYER (TARUH DI PLAYER.GD) ---
func eksekusi_stealth_kill():
if is_dead or is_menunduk or sedang_di_tangga: return
set_physics_process(false)
print("🥷 Player: Memulai Stealth Kill. Mengeluarkan pisau...")
if sprite_pisau:
sprite_pisau.visible = true
if anim_player and anim_player.has_animation("tusuk"):
anim_player.play("tusuk")
await anim_player.animation_finished # Menunggu animasi tusuk kelar
else:
print("⚠️ Peringatan: Animasi bernama 'tusuk' tidak ditemukan!")
if sprite_pisau:
sprite_pisau.visible = false
set_physics_process(true)
print("🥷 Player: Stealth Kill selesai.")