Files
Cozypaw-Hospital/scripts/systems/drag_drop_component.gd
Steven Wroblewski f7c8a7ec03 fix(poc): resolve evaluator and review findings
- Add RectangleShape2D to Character and InteractiveObject collision areas
- Fix HUD button signal connections in _ready()
- Fix character_placed signal emitting global_position
- Extract DEFAULT_DRAG_RADIUS constant in DragDropComponent
- Type Variant on JSON parsed variable in SaveManager
- Extract music symbol constants in HUD
- Refactor duplicated drag input code in InputManager

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 11:16:05 +02:00

82 lines
2.7 KiB
GDScript

## DragDropComponent — reusable drag-and-drop node; attach to any Character or InteractiveObject.
class_name DragDropComponent extends Node
signal drag_picked_up(global_position: Vector2)
signal drag_released(global_position: Vector2)
const DRAG_Z_INDEX: int = 10
const DRAG_SCALE: float = 1.1
const DEFAULT_DRAG_RADIUS: float = 64.0
@export var drag_target: Node2D
var _is_dragging: bool = false
var _drag_offset: Vector2 = Vector2.ZERO
var _original_z_index: int = 0
var _original_scale: Vector2 = Vector2.ONE
func _ready() -> void:
if drag_target == null:
drag_target = get_parent() as Node2D
func _input(event: InputEvent) -> void:
if event is InputEventScreenTouch:
_handle_press(event.pressed, event.position)
elif event is InputEventScreenDrag and _is_dragging:
_move_to(event.position)
elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
_handle_press(event.pressed, event.position)
elif event is InputEventMouseMotion and _is_dragging:
_move_to(event.position)
func _handle_press(pressed: bool, screen_pos: Vector2) -> void:
if pressed and _is_position_over_target(screen_pos):
_start_drag(screen_pos)
elif not pressed and _is_dragging:
_end_drag(screen_pos)
func _start_drag(screen_pos: Vector2) -> void:
_is_dragging = true
var world_pos: Vector2 = _screen_to_world(screen_pos)
_drag_offset = drag_target.global_position - world_pos
_original_z_index = drag_target.z_index
_original_scale = drag_target.scale
drag_target.z_index = DRAG_Z_INDEX
drag_target.scale = _original_scale * DRAG_SCALE
drag_picked_up.emit(drag_target.global_position)
func _end_drag(_screen_pos: Vector2) -> void:
_is_dragging = false
drag_target.z_index = _original_z_index
drag_target.scale = _original_scale
drag_released.emit(drag_target.global_position)
func _move_to(screen_pos: Vector2) -> void:
var world_pos: Vector2 = _screen_to_world(screen_pos)
drag_target.global_position = world_pos + _drag_offset
func _screen_to_world(screen_pos: Vector2) -> Vector2:
var canvas_transform: Transform2D = drag_target.get_viewport().get_canvas_transform()
return canvas_transform.affine_inverse() * screen_pos
func _is_position_over_target(screen_pos: Vector2) -> bool:
if drag_target == null:
return false
var world_pos: Vector2 = _screen_to_world(screen_pos)
var local_pos: Vector2 = drag_target.to_local(world_pos)
var area: Area2D = drag_target.get_node_or_null("CollisionArea") as Area2D
if area == null:
return local_pos.length() < DEFAULT_DRAG_RADIUS
for child in area.get_children():
if child is CollisionShape2D and child.shape != null:
return child.shape.get_rect().has_point(local_pos)
return local_pos.length() < DEFAULT_DRAG_RADIUS