class_name Player extends CharacterBody2D @export var move_speed : float = 50.0; var heart_attack : PackedScene = preload("res://scenes/hearts.tscn") var scithe_attack : PackedScene = preload("res://scenes/scithe_attack.tscn") var spit_attack : PackedScene = preload("res://scenes/spit.tscn") var death_explosion := preload("res://scenes/player_explosion.tscn") var dash := false var dash_base_cd = 0.7 var dash_cd = 0 var health = 3 var mask_start_time = 10 var mask_time_remaining = 15 var charge : float = 0.0 @export var charge_time : float = 0.5 @onready var sprite = $AnimatedSprite2D const INTERACT_DIST = 60.0 var current_mask : Types.mask_types = Types.mask_types.Melee var last_mask : MaskDrop var closest_mask : MaskDrop func _ready() -> void: EventBus.health_changed.emit(health) func _check_items(): var masks = get_tree().get_nodes_in_group("mask") closest_mask = null var min_dist = INF for mask in masks: var dist = global_position.distance_to(mask.global_position) if dist < INTERACT_DIST + 10: min_dist = dist closest_mask = mask if closest_mask != last_mask: if last_mask and last_mask.has_method("hide_popup"): last_mask.hide_popup() last_mask = closest_mask if closest_mask: if min_dist < INTERACT_DIST: if closest_mask.has_method("show_popup"): closest_mask.show_popup() else: if closest_mask.has_method("hide_popup"): closest_mask.hide_popup() func _physics_process(delta: float) -> void: EventBus.health_changed.emit(health) var input_vector = Vector2.ZERO input_vector.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") input_vector.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up") if dash: #var dir = global_position.direction_to(get_global_mouse_position()) velocity += input_vector * move_speed * 40 dash = false var tween = create_tween() tween.set_ease(Tween.EASE_IN_OUT) tween.tween_property($AnimatedSprite2D, "scale:x", 0.5, 0.1) tween.tween_property($AnimatedSprite2D, "scale:x", 1, 0.1) input_vector = input_vector.normalized() if input_vector != Vector2.ZERO: velocity += input_vector * move_speed velocity *= 0.7 move_and_slide() func hit(): health -= 1 EventBus.health_changed.emit(health) if health == 0: die() EventBus.player_dmg.emit() func die(): EventBus.screenshake.emit(5) var explo = death_explosion.instantiate() get_parent().add_child(explo) explo.global_position = global_position explo.emitting = true visible = false get_tree().create_timer(2).timeout.connect(SceneTransition.change_scene.bind("res://start_menu.tscn"), true) process_mode = Node.PROCESS_MODE_DISABLED func _process(delta: float) -> void: charge += delta dash_cd += delta var enemies = len(get_tree().get_nodes_in_group("enemy")) if enemies > 0: mask_time_remaining -= delta if mask_time_remaining < 0: mask_time_remaining = 10 die() EventBus.mask_time_changed.emit(mask_time_remaining / mask_start_time) _check_items() update_arrow_direction() func update_arrow_direction() -> void: var enemies = get_tree().get_nodes_in_group("enemy") var closest_enemy: Node2D = null var shortest_dist: float = INF # Start with infinity var arrow = $Arrow # 1. Find the closest enemy for enemy in enemies: if enemy is Node2D: var dist = global_position.distance_to(enemy.global_position) if dist < shortest_dist: shortest_dist = dist closest_enemy = enemy # 2. Logic: Only show/rotate if they are far away if closest_enemy and shortest_dist > 250: arrow.visible = true arrow.look_at(closest_enemy.global_position) else: # Hide the arrow if no enemy exists or they are within 350px arrow.visible = false func collect_mask(mask : MaskDrop): if mask: mask.collect(global_position) EventBus.mask_changed.emit(mask.mask_type) $AnimatedSprite2D.switch_mask(mask.mask_type) current_mask = mask.mask_type mask_time_remaining = mask_start_time func launch_atk(): var atk = null if (current_mask == Types.mask_types.Melee): atk = scithe_attack.instantiate() add_child(atk) atk.look_at(get_global_mouse_position()) SoundManager.play_sfx("swing") elif (current_mask == Types.mask_types.Ranged): atk = heart_attack.instantiate() atk.global_position = global_position atk.look_at(get_global_mouse_position()) SoundManager.play_sfx("heart") get_parent().add_child(atk) elif (current_mask == Types.mask_types.Spit): atk = spit_attack.instantiate() atk.global_position = global_position atk.start_position = global_position get_parent().add_child(atk) atk.target_position = get_global_mouse_position() atk.set_from_player(true) atk.global_position = atk.global_position.move_toward(get_global_mouse_position(), 10 ) EventBus.mask_time_changed.emit(mask_time_remaining) func _input(event: InputEvent) -> void: if (event.is_action_pressed("dash")): if (dash_cd > dash_base_cd): dash = true dash_cd = 0 if (event.is_action_pressed("attack")): if (charge > charge_time): charge = 0 launch_atk() if (event.is_action_pressed("interact")): if closest_mask: collect_mask(closest_mask)