xiandie/scene/entity/ux/hover_light_click_area.gd

89 lines
2.1 KiB
GDScript3
Raw Normal View History

2025-07-14 10:50:05 +00:00
class_name HoverLightClickArea extends Area2D
2025-07-14 14:23:21 +00:00
signal interacted
2025-07-14 10:50:05 +00:00
@export var freezing := false:
set(val):
freezing = val
if freezing and touching:
_on_mouse_exited()
var touching = false
2025-07-14 14:23:21 +00:00
static var _focus_mutex = Mutex.new()
2025-07-14 10:50:05 +00:00
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:
2025-07-14 14:23:21 +00:00
lights.append(self.get_path_to(c))
2025-07-14 10:50:05 +00:00
if lights.is_empty():
2025-07-14 14:23:21 +00:00
printerr("HoverLightButton has no PointLight2D children. auto freezed name=", name)
freezing = true
2025-07-14 10:50:05 +00:00
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(_on_mouse_exited)
2025-07-14 14:23:21 +00:00
# 默认先熄灭
_toggle_light(false)
2025-07-14 10:50:05 +00:00
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
2025-07-14 14:23:21 +00:00
_focus_mutex.lock()
2025-07-14 10:50:05 +00:00
# 尝试获得 current_focusing_item
if current_focusing_item != "":
if not pending_enter_callables.has(_on_mouse_entered):
pending_enter_callables.append(_on_mouse_entered)
2025-07-14 14:23:21 +00:00
_focus_mutex.unlock()
2025-07-14 10:50:05 +00:00
return false
current_focusing_item = name
2025-07-14 14:23:21 +00:00
_focus_mutex.unlock()
2025-07-14 10:50:05 +00:00
_toggle_light(true)
return true
func _on_mouse_exited() -> void:
touching = false
2025-07-14 14:23:21 +00:00
_focus_mutex.lock()
2025-07-14 10:50:05 +00:00
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
2025-07-14 14:23:21 +00:00
_focus_mutex.unlock()
2025-07-14 10:50:05 +00:00
_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
2025-07-14 14:23:21 +00:00
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()