class_name HoverLightClickArea extends Area2D signal interacted @export var freezing := false: set(val): freezing = val if freezing and touching: _on_mouse_exited() var touching = false static var _focus_mutex = Mutex.new() static var current_focusing_item = "": set(val): current_focusing_item = val if GlobalConfig.DEBUG: print("HoverLightClickArea current_focusing_item=", current_focusing_item) static var pending_enter_callables := [] as Array[Callable] # to pointlight2d var lights: Array[NodePath] = [] func _ready() -> void: for c in get_children(): if c is PointLight2D: lights.append(self.get_path_to(c)) if lights.is_empty(): printerr("HoverLightButton has no PointLight2D children. auto freezed name=", name) freezing = true mouse_entered.connect(_on_mouse_entered) mouse_exited.connect(_on_mouse_exited) # 默认先熄灭 _toggle_light(false) func is_focused() -> bool: return current_focusing_item == name func _on_mouse_entered() -> bool: touching = true if freezing or not is_visible_in_tree(): return false if is_focused(): return true _focus_mutex.lock() # 尝试获得 current_focusing_item if current_focusing_item != "": if not pending_enter_callables.has(_on_mouse_entered): pending_enter_callables.append(_on_mouse_entered) _focus_mutex.unlock() return false current_focusing_item = name _focus_mutex.unlock() _toggle_light(true) return true func _on_mouse_exited() -> void: touching = false _focus_mutex.lock() pending_enter_callables.erase(_on_mouse_entered) # frezzing 不影响 mouse exited if is_focused(): current_focusing_item = "" for c in pending_enter_callables: if c.call(): break _focus_mutex.unlock() _toggle_light(false) func _toggle_light(on: bool) -> void: for l in lights: var light = get_node(l) as PointLight2D if light: light.enabled = on func _input(event: InputEvent) -> void: if freezing or Engine.is_editor_hint() or not is_visible_in_tree(): return if event is InputEventMouseButton: if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: # get_viewport().set_input_as_handled() if is_focused(): interacted.emit()