extends Node2D const ACTION_INTERACT := "interact" @onready var player: Player = get_tree().get_first_node_in_group("player") @onready var label: Label = $Label var base_prompt_text: String = "" var areas_in_range: Array[InteractionArea] = [] var can_interact: bool = true func _ready() -> void: base_prompt_text = _build_base_prompt_text() label.hide() func register_area(area: InteractionArea) -> void: areas_in_range.push_back(area) func unregister_area(area: InteractionArea) -> void: var index := areas_in_range.find(area) if index != -1: areas_in_range.remove_at(index) func _process(_delta: float) -> void: if not can_interact: label.hide() return var nearest := _get_nearest_area() if nearest: label.text = "%s%s" % [base_prompt_text, nearest.action_name] label.show() else: label.hide() func _input(event: InputEvent) -> void: if not (can_interact and event.is_action_pressed(ACTION_INTERACT)): return var nearest := _get_nearest_area() if nearest: can_interact = false label.hide() await nearest.interact.call() can_interact = true func _get_nearest_area() -> InteractionArea: if areas_in_range.is_empty(): return null areas_in_range.sort_custom(self._compare_by_distance_to_player) return areas_in_range[0] func _compare_by_distance_to_player(a: InteractionArea, b: InteractionArea) -> bool: var d1 := player.global_position.distance_to(a.global_position) var d2 := player.global_position.distance_to(b.global_position) return d1 < d2 func _build_base_prompt_text() -> String: var events := InputMap.action_get_events(ACTION_INTERACT) if events.is_empty(): return "Interact with " return "%s to " % [events[0].as_text()]