@tool class_name Sign extends TextureRect # @export var texture: Texture: # set(val): # texture = val # sprite2d.texture = texture # # @export var base_scale := Vector2.ONE: # # set(val): # # base_scale = val # # sprite2d.scale = base_scale @export var show_sign := true: set(val): show_sign = val if val: modulate.a = 1.0 else: modulate.a = 0.0 signal interacted signal cancel # 同时只能有一个物品被激活交互态,其他物品进入等待队列 static var occupied: NodePath static var _pending_activate_sign := [] as Array[NodePath] # 使用互斥锁保证线程安全。在操作 occupied 或 _pending_activate_sign 时需要先锁定,操作完成后解锁 static var mutex = Mutex.new() var activated = false # var sprite2d = Sprite2D.new() var base_scale = Vector2.ONE func _ready() -> void: base_scale = scale # layer = GlobalConfig.CANVAS_LAYER_FG var point_light = get_node_or_null("../PointLight2D") if point_light: point_light.energy = 0.0 var area2d = get_node_or_null("../Area2D") if area2d: area2d.body_entered.connect(activate) area2d.body_exited.connect(disactivate) if not Engine.is_editor_hint(): modulate.a = 0 # func _load_sprite() -> void: # sprite2d.texture = texture # sprite2d.scale = base_scale func activate(_body: Node2D) -> void: # point_light.energy = 1.0 if not is_node_ready(): await ready var path := get_path() mutex.lock() if occupied and occupied != path: _pending_activate_sign.append(path) mutex.unlock() return else: occupied = path activated = true mutex.unlock() if activated and show_sign: var tween = create_tween() tween.tween_property(self, "modulate:a", 1.0, 0.2) var p_tween = tween.parallel() p_tween.tween_property(self, "scale", base_scale * Vector2(1.2, 1.2), 0.3) p_tween.tween_property(self, "scale", base_scale, 0.1) # if activated: # focus_mode = FOCUS_ALL # grab_focus() func disactivate(_body: Node2D) -> void: # release_focus() mutex.lock() if activated: activated = false occupied = "" while _pending_activate_sign.size() > 0: var path = _pending_activate_sign.pop_front() var _sign = get_node_or_null(path) if _sign: _sign.activate(null) break else: # make sure the sign is not in the pending list _pending_activate_sign.erase(get_path()) # double check. because the sign may be activated by other body if activated: disactivate(_body) mutex.unlock() # point_light.energy = 0.0 if show_sign: create_tween().tween_property(self, "modulate:a", 0.0, 0.2) func _unhandled_input(event: InputEvent) -> void: if activated: if event.is_action_pressed("interact"): interacted.emit() elif event.is_action_pressed("cancel"): cancel.emit() get_viewport().set_input_as_handled()