122 lines
2.8 KiB
GDScript3
122 lines
2.8 KiB
GDScript3
|
@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 = ""
|
||
|
|
||
|
signal picked
|
||
|
signal dropped
|
||
|
|
||
|
# z +1 when picked (-1 when dropped)
|
||
|
# @export var z_up_on_picked := true
|
||
|
@export var item_name = ""
|
||
|
@export var collision_shape: RectangleShape2D
|
||
|
@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 and holding:
|
||
|
_drop()
|
||
|
@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
|
||
|
$CollisionShape2D.shape = collision_shape
|
||
|
if Engine.is_editor_hint():
|
||
|
queue_redraw()
|
||
|
return
|
||
|
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:
|
||
|
return
|
||
|
# 尝试获得 current_focusing_item
|
||
|
if current_focusing_item != "":
|
||
|
return
|
||
|
current_focusing_item = item_name
|
||
|
touching = true
|
||
|
_toggle_outline(true)
|
||
|
|
||
|
|
||
|
func _on_mouse_exited() -> void:
|
||
|
if freezing:
|
||
|
return
|
||
|
if touching and not holding:
|
||
|
current_focusing_item = ""
|
||
|
touching = false
|
||
|
_toggle_outline(false)
|
||
|
|
||
|
|
||
|
func _input(event: InputEvent) -> void:
|
||
|
if freezing or Engine.is_editor_hint():
|
||
|
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 current_focusing_item != item_name:
|
||
|
return
|
||
|
# reset rotation
|
||
|
rotation = 0
|
||
|
_toggle_outline(false)
|
||
|
holding = true
|
||
|
# z_index += 1
|
||
|
picked.emit()
|
||
|
_update_pos_to_mouse()
|
||
|
|
||
|
|
||
|
func _drop() -> void:
|
||
|
if holding:
|
||
|
holding = false
|
||
|
# z_index -= 1
|
||
|
dropped.emit()
|
||
|
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)
|