117 lines
3.0 KiB
GDScript
117 lines
3.0 KiB
GDScript
@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()
|
||
if is_inside_tree():
|
||
# grab focus 放在 emit 后面,避免在 emit 时 prop hud 失去 focus
|
||
# 传送时会导致 is_inside_tree 为 false,此时也无需与 prop hud 抢占 focus
|
||
focus_mode = FOCUS_ALL
|
||
grab_focus()
|
||
elif event.is_action_pressed("cancel"):
|
||
cancel.emit()
|
||
release_focus()
|
||
var viewport = get_viewport()
|
||
if viewport:
|
||
viewport.set_input_as_handled()
|