@tool # A draggable item in the game that can be picked up and displayed with an outline effect. class_name Draggable2D extends Area2D static var current_focusing_item = "" # pass self signal picked(node: Draggable2D) signal dropped(node: Draggable2D) # 表现为按钮,即点击发送 picked 信号 @export var act_as_button := false # z +1 when picked (-1 when dropped) # @export var z_up_on_picked := true @export var item_name = "" @export var sprite_offset := Vector2(0, 0): set(val): sprite_offset = val if is_node_ready(): sprite.offset = sprite_offset @export var freezing := false: set(val): freezing = val if freezing: if holding: _drop() elif touching: _on_mouse_exited() @export var texture: Texture2D: # The texture to display for the item set(val): texture = val if is_node_ready(): sprite.texture = texture @export var limit_rect := Rect2(Vector2.ZERO, Vector2(564, 316)) @onready var sprite = $Sprite2D as Sprite2D func _ready() -> void: sprite.texture = texture sprite.offset = sprite_offset if Engine.is_editor_hint(): return _toggle_outline(false) var collision2d = get_node_or_null("CollisionShape2D") if not collision2d: push_error("CollisionShape2D node not found in Draggable2D", self) collision2d = CollisionShape2D.new() add_child(collision2d) collision2d.shape = RectangleShape2D.new() mouse_entered.connect(_on_mouse_entered) mouse_exited.connect(_on_mouse_exited) # Whether the item is currently being held by the player var holding = false var touching = false func _on_mouse_entered() -> void: if freezing or not is_visible_in_tree(): return # 尝试获得 current_focusing_item if current_focusing_item != "": return current_focusing_item = item_name touching = true _toggle_outline(true) func _on_mouse_exited() -> void: # frezzing 不影响 mouse exited if touching and not holding: current_focusing_item = "" touching = false _toggle_outline(false) func _notification(what: int) -> void: if what == NOTIFICATION_PREDELETE: if holding: _drop() elif touching: _on_mouse_exited() 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: # Trigger the pick action if touching and not holding: _try_pick() elif holding: _drop() elif holding and event is InputEventMouseMotion: _update_pos_to_mouse() func _update_pos_to_mouse(): # update global position global_position = get_global_mouse_position() global_position.x = clamp(global_position.x, limit_rect.position.x, limit_rect.end.x) global_position.y = clamp(global_position.y, limit_rect.position.y, limit_rect.end.y) func _try_pick() -> void: if act_as_button: # 作为按钮,发送 picked 信号 picked.emit(self) var tween = create_tween() tween.tween_property(sprite.material, "shader_parameter/alpha_ratio", 0.5, 0.15) tween.tween_property(sprite.material, "shader_parameter/alpha_ratio", 1.0, 0.15) return if current_focusing_item != item_name: return # reset rotation rotation = 0 _toggle_outline(false) holding = true # z_index += 1 picked.emit(self) _update_pos_to_mouse() func _drop() -> void: if holding: holding = false # z_index -= 1 dropped.emit(self) if touching: _toggle_outline(true) else: # not touching but dropped, remove current_focusing_item if any current_focusing_item = "" func _toggle_outline(display = true): var tween = create_tween() if display: tween.tween_property(sprite.material, "shader_parameter/thickness", 1.0, 0.2) else: tween.tween_property(sprite.material, "shader_parameter/thickness", 0.0, 0.2)