feat: nearest card selection
This commit is contained in:
parent
1939e49a91
commit
46f7463267
|
|
@ -73,4 +73,3 @@ func unload():
|
|||
## Override in subclasses to add custom scene preparation logic
|
||||
func prepare_scene_start(_scene_id: Scenes.id, _is_repeating: bool) -> void:
|
||||
await get_tree().process_frame # Dummy wait for LSP warning otherwise
|
||||
|
||||
|
|
|
|||
|
|
@ -40,17 +40,12 @@ var mementos_collected: int = 0:
|
|||
|
||||
var selection: Draggable = null:
|
||||
set(value):
|
||||
# this makes sure no accidental context switches can happen while a card is being dragged
|
||||
if current_context == DRAG: return
|
||||
if selection == value: return
|
||||
|
||||
# Deselect current
|
||||
if selection:
|
||||
selection.highlighted = false
|
||||
|
||||
# Select new
|
||||
# Select & highlight new
|
||||
if selection: selection.highlighted = false
|
||||
selection = value
|
||||
if selection:
|
||||
selection.highlighted = true
|
||||
if selection: selection.highlighted = true
|
||||
|
||||
# Are we selecting cards or stickies?
|
||||
if selection is Card:
|
||||
|
|
@ -88,6 +83,7 @@ func _smooth(current: Vector2, goal: Vector2, delta: float) -> Vector2:
|
|||
var k := pow(0.1, 60.0 * delta)
|
||||
return (1.0-k) * current + k * goal
|
||||
|
||||
|
||||
func _process(delta: float):
|
||||
var zone_position := Vector2(notezone.get_screen_position().x + sticky_width / 3.0, sticky_height)
|
||||
|
||||
|
|
@ -207,24 +203,21 @@ func is_in_dropzone(to_check: Draggable) -> bool:
|
|||
|
||||
|
||||
# Called by notes when a mouse event needs handling
|
||||
func handle_mouse_button(input: InputEventMouseButton, to_handle = selection) -> void:
|
||||
# Prevent dragging multiple nodes at once
|
||||
if current_context == DRAG and selection:
|
||||
return
|
||||
func handle_mouse_button(input: InputEventMouseButton, target: Draggable) -> void:
|
||||
|
||||
# === DRAG START ===
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and input.pressed:
|
||||
_start_drag(to_handle)
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and input.is_pressed():
|
||||
_start_drag(target)
|
||||
return
|
||||
|
||||
# === DRAG END ===
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and not input.pressed:
|
||||
_end_drag(to_handle)
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and not input.is_released():
|
||||
_end_drag(target)
|
||||
return
|
||||
|
||||
|
||||
## Starts a drag operation for the given draggable
|
||||
func _start_drag(draggable: Dragg able) -> void:
|
||||
func _start_drag(draggable: Draggable) -> void:
|
||||
selection = draggable
|
||||
current_context = DRAG
|
||||
|
||||
|
|
@ -234,24 +227,36 @@ func _start_drag(draggable: Dragg able) -> void:
|
|||
|
||||
## Ends a drag operation and handles the drop
|
||||
func _end_drag(draggable: Draggable) -> void:
|
||||
if not draggable: return
|
||||
|
||||
draggable.end_drag()
|
||||
|
||||
# Let draggable find its own drop target
|
||||
var drop_target := draggable.find_drop_target()
|
||||
|
||||
# Execute the drop
|
||||
if drop_target and Draggable.is_drop_target(drop_target):
|
||||
var result = drop_target.handle_drop(draggable)
|
||||
pass
|
||||
selection = draggable
|
||||
|
||||
# Cleanup and state update
|
||||
current_context = NAVIGATE
|
||||
|
||||
var destination := draggable.end_drag()
|
||||
|
||||
if not destination and draggable is StickyNote:
|
||||
# reclaim if necessary
|
||||
pass
|
||||
|
||||
if destination and destination is Card:
|
||||
# attach / unattach
|
||||
pass
|
||||
|
||||
if destination and destination is StickyNote:
|
||||
# unattach and attach to parent
|
||||
pass
|
||||
|
||||
# Let draggable find its own drop target
|
||||
#var drop_target := draggable.find_drop_target()
|
||||
|
||||
# Execute the drop
|
||||
#if drop_target and Draggable.is_drop_target(drop_target):
|
||||
# var result = drop_target.handle_drop(draggable)
|
||||
# pass
|
||||
|
||||
# Check win condition if sticky was attached to card
|
||||
if draggable is StickyNote and draggable.is_attached:
|
||||
check_board_comnpletion()
|
||||
check_board_completion()
|
||||
|
||||
|
||||
func reclaim_sticky(note: StickyNote):
|
||||
|
|
@ -259,7 +264,7 @@ func reclaim_sticky(note: StickyNote):
|
|||
notes.append(note)
|
||||
|
||||
|
||||
func check_board_comnpletion():
|
||||
func check_board_completion():
|
||||
if is_board_complete():
|
||||
if not board_was_completed:
|
||||
board_was_completed = true
|
||||
|
|
@ -316,20 +321,44 @@ func give_lore_feedback():
|
|||
complete = true
|
||||
|
||||
# Mark area that was hovered over as currently selected
|
||||
func handle_hover(to_handle: Area2D) -> void:
|
||||
func handle_hover(draggable: Draggable) -> void:
|
||||
|
||||
# If we're hovering with the mouse without clicking, that updates our selection
|
||||
if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): selection = to_handle
|
||||
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): return
|
||||
|
||||
|
||||
func _sort_by_proximity_and_depth(draggables: Array) -> Array[Draggable]:
|
||||
var result : Array[Draggable] = []
|
||||
result.append_array(draggables)
|
||||
result.sort_custom(_by_mouse)
|
||||
var depth := len(result) * 2
|
||||
for item in result:
|
||||
depth -= 1
|
||||
item.z_index = depth
|
||||
return result
|
||||
|
||||
|
||||
func _nearest_hovered(candidates: Array[Draggable]) -> Draggable:
|
||||
for candidate in candidates:
|
||||
if candidate.mouse_over: return candidate
|
||||
return null
|
||||
|
||||
|
||||
|
||||
func _spatial(a: Draggable, b: Draggable) -> bool:
|
||||
|
||||
func _by_spatial(a: Draggable, b: Draggable) -> bool:
|
||||
return a.position.x + a.position.y * 100 > b.position.x + b.position.y * 100
|
||||
|
||||
|
||||
func _by_mouse(a: Draggable, b: Draggable) -> bool:
|
||||
var mouse_pos : Vector2 = get_viewport().get_mouse_position()
|
||||
return (a.position-mouse_pos).length() < (b.position-mouse_pos).length()
|
||||
|
||||
|
||||
## Call this after bulk loading to fix child order / z-index issues
|
||||
func _sort_by_positions() -> void:
|
||||
cards.sort_custom(_spatial)
|
||||
notes.sort_custom(_spatial)
|
||||
cards.sort_custom(_by_spatial)
|
||||
notes.sort_custom(_by_spatial)
|
||||
|
||||
|
||||
# === DROP TARGET PATTERN IMPLEMENTATION ===
|
||||
|
|
@ -348,18 +377,16 @@ func handle_drop(draggable: Draggable) -> int:
|
|||
|
||||
# Takes the inputs for control inputs
|
||||
func _input(event) -> void:
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
if event is InputEventAction and event.is_action_pressed("ui_cancel"):
|
||||
closed.emit()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
if event is InputEventMouse:
|
||||
# makes sure to pass release events so notes do not get attached to the mouse while the cursor leaves the area.
|
||||
if event is InputEventMouseButton and current_context == DRAG:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
|
||||
handle_mouse_button(event)
|
||||
get_viewport().set_input_as_handled()
|
||||
else:
|
||||
return
|
||||
|
||||
if event is InputEventMouseMotion and not event.is_action_pressed("mouse_left"):
|
||||
var candidate := _nearest_hovered(_sort_by_proximity_and_depth(notes))
|
||||
if not candidate:
|
||||
candidate = _nearest_hovered(_sort_by_proximity_and_depth(cards))
|
||||
selection = candidate
|
||||
|
||||
|
||||
## Saves board state directly to SaveGame resource
|
||||
|
|
|
|||
|
|
@ -38,55 +38,41 @@ var transfor_arr: Array[Transform2D] = [
|
|||
@onready var background_sprite: AnimatedSprite2D = $AnimatedSprite2D
|
||||
|
||||
@export var picked_random: bool = false
|
||||
|
||||
@export var wiggle_strength: float = 0.2
|
||||
@export var wiggle_speed: float = 5
|
||||
@export_range(1, 2) var scale_bump: float = 1.05
|
||||
@export_range(1.0, 10.0) var bounce_speed: float = 5
|
||||
@export_range(1.0, 2.0) var highlight_brightness: float = 1.4
|
||||
|
||||
@export_color_no_alpha var highlight_color: Color = Color(1.4, 1.4, 1.4)
|
||||
|
||||
## Override set_highlight to add visual feedback for cards
|
||||
func set_highlight(value: bool) -> void:
|
||||
if value != _highlighted:
|
||||
_highlighted = value
|
||||
if value == _highlighted: return
|
||||
_highlighted = value
|
||||
|
||||
if scale_tween: scale_tween.kill()
|
||||
if wiggle_tween: wiggle_tween.kill()
|
||||
if brightness_tween: brightness_tween.kill()
|
||||
|
||||
if _highlighted:
|
||||
scale_tween = get_tree().create_tween()
|
||||
scale_tween.tween_property(self, "scale", Vector2(scale_bump, scale_bump), 0.1)
|
||||
wiggle_tween = get_tree().create_tween()
|
||||
wiggle_tween.tween_property(self, "wiggle_intensity", 1, 0.2)
|
||||
brightness_tween = get_tree().create_tween()
|
||||
brightness_tween.set_parallel(true)
|
||||
brightness_tween.tween_property(background_sprite, "modulate", highlight_color, 0.15)
|
||||
brightness_tween.tween_property(label, "modulate", highlight_color, 0.15)
|
||||
else:
|
||||
scale_tween = get_tree().create_tween()
|
||||
scale_tween.tween_property(self, "scale", Vector2(1, 1), 0.3)
|
||||
wiggle_tween = get_tree().create_tween()
|
||||
wiggle_tween.tween_property(self, "wiggle_intensity", 0, 0.5)
|
||||
brightness_tween = get_tree().create_tween()
|
||||
brightness_tween.set_parallel(true)
|
||||
brightness_tween.tween_property(background_sprite, "modulate", Color.WHITE, 0.2)
|
||||
brightness_tween.tween_property(label, "modulate", Color.WHITE, 0.2)
|
||||
|
||||
if is_inside_tree() and is_node_ready():
|
||||
if scale_tween: scale_tween.kill()
|
||||
if wiggle_tween: wiggle_tween.kill()
|
||||
if brightness_tween: brightness_tween.kill()
|
||||
if _highlighted:
|
||||
scale_tween = get_tree().create_tween()
|
||||
scale_tween.tween_property(self, "scale", Vector2(scale_bump, scale_bump), 0.1)
|
||||
wiggle_tween = get_tree().create_tween()
|
||||
wiggle_tween.tween_property(self, "wiggle_intensity", 1, 0.2)
|
||||
brightness_tween = get_tree().create_tween()
|
||||
brightness_tween.set_parallel(true)
|
||||
brightness_tween.tween_property(background_sprite, "modulate", Color(highlight_brightness, highlight_brightness, highlight_brightness), 0.15)
|
||||
brightness_tween.tween_property(label, "modulate", Color(highlight_brightness, highlight_brightness, highlight_brightness), 0.15)
|
||||
else:
|
||||
scale_tween = get_tree().create_tween()
|
||||
scale_tween.tween_property(self, "scale", Vector2(1, 1), 0.3)
|
||||
wiggle_tween = get_tree().create_tween()
|
||||
wiggle_tween.tween_property(self, "wiggle_intensity", 0, 0.5)
|
||||
brightness_tween = get_tree().create_tween()
|
||||
brightness_tween.set_parallel(true)
|
||||
brightness_tween.tween_property(background_sprite, "modulate", Color.WHITE, 0.2)
|
||||
brightness_tween.tween_property(label, "modulate", Color.WHITE, 0.2)
|
||||
else:
|
||||
if _highlighted:
|
||||
scale = Vector2(scale_bump, scale_bump)
|
||||
wiggle_intensity = 1
|
||||
if background_sprite:
|
||||
background_sprite.modulate = Color(highlight_brightness, highlight_brightness, highlight_brightness)
|
||||
if label:
|
||||
label.modulate = Color(highlight_brightness, highlight_brightness, highlight_brightness)
|
||||
else:
|
||||
scale = Vector2(1,1)
|
||||
wiggle_intensity = 0
|
||||
if background_sprite:
|
||||
background_sprite.modulate = Color.WHITE
|
||||
if label:
|
||||
label.modulate = Color.WHITE
|
||||
|
||||
@export var voice_line: AudioStream = null
|
||||
@export var is_dragable: bool = false
|
||||
|
|
@ -158,6 +144,7 @@ func init(card_name: String = "card", own_id:StringName = "-1") -> void:
|
|||
|
||||
|
||||
func _ready():
|
||||
super._ready()
|
||||
input_event.connect(_on_input_event)
|
||||
|
||||
_handle_wiggle(0)
|
||||
|
|
@ -202,7 +189,6 @@ func _process(delta: float) -> void:
|
|||
|
||||
func _handle_wiggle(delta):
|
||||
wiggle_pos += delta * wiggle_speed * wiggle_intensity
|
||||
|
||||
rotation = noise.get_noise_1d(wiggle_pos)*wiggle_strength
|
||||
|
||||
|
||||
|
|
@ -212,26 +198,18 @@ func _input(event: InputEvent) -> void:
|
|||
is_dragged = false
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
if not Input.is_action_pressed("mouse_left"):
|
||||
# Do nothing if mouse hovers over sticky_note (it has higher priority)
|
||||
var sticky = get_attached_sticky_note()
|
||||
if sticky and sticky.highlighted:
|
||||
return
|
||||
var board = _get_board()
|
||||
if board:
|
||||
board.handle_hover(self)
|
||||
super._on_mouse_entered()
|
||||
|
||||
func _on_mouse_exited():
|
||||
highlighted = false
|
||||
super._on_mouse_exited()
|
||||
if burn_state == burned.SINGED:
|
||||
burn_state = burned.NOT
|
||||
|
||||
func _on_input_event(_viewport, event, _shape_idx):
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
var board = _get_board()
|
||||
if board and highlighted:
|
||||
if highlighted:
|
||||
mouse_offset = get_viewport().get_mouse_position() - position
|
||||
board.handle_mouse_button(event, self)
|
||||
if _get_board(): _get_board().handle_mouse_button(event, self)
|
||||
|
||||
func _move_card():
|
||||
if is_dragged:
|
||||
|
|
@ -284,19 +262,6 @@ func exchange_sticky_note_with(new_note: StickyNote) -> StickyNote:
|
|||
attach_sticky_note(new_note)
|
||||
return tmp
|
||||
|
||||
# This makes sure this node highlights itself when focus has left the sticky note.
|
||||
func check_hover():
|
||||
# Re-trigger hover handling - parent will decide if this should be highlighted
|
||||
_on_mouse_entered()
|
||||
|
||||
func reclaim_sticky_note():
|
||||
var sticky = get_attached_sticky_note()
|
||||
if not sticky:
|
||||
return
|
||||
sticky.tween_transform_to(Transform2D(0, to_global(sticky_note_position)))
|
||||
await sticky.transform_tween_finished
|
||||
sticky.reparent(self)
|
||||
|
||||
|
||||
# === DROP TARGET PATTERN IMPLEMENTATION ===
|
||||
|
||||
|
|
@ -348,7 +313,7 @@ func find_drop_target() -> Node:
|
|||
|
||||
## Walks up the scene tree to find the CardBoard
|
||||
func _get_board() -> CardBoard:
|
||||
var node = get_parent()
|
||||
var node := get_parent()
|
||||
while node:
|
||||
if node is CardBoard:
|
||||
return node
|
||||
|
|
|
|||
|
|
@ -39,6 +39,3 @@ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 3
|
||||
|
||||
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ enum DropResult {
|
|||
EXCHANGED # Swap occurred, exchanged item needs handling
|
||||
}
|
||||
|
||||
var mouse_over: bool = false
|
||||
|
||||
var is_dragged: bool = false:
|
||||
set(dragged):
|
||||
is_dragged = dragged
|
||||
|
|
@ -37,9 +39,35 @@ var _drag_start_position: Vector2
|
|||
var _mouse_drag_offset: Vector2
|
||||
var _drag_source: Node = null # Where the drag started from
|
||||
|
||||
## === SETUP ###
|
||||
func _ready() -> void:
|
||||
mouse_entered.connect(_on_mouse_entered)
|
||||
mouse_exited.connect(_on_mouse_exited)
|
||||
|
||||
|
||||
func _get_hover_handler() -> Node:
|
||||
var parent := get_parent()
|
||||
while parent and not parent.has_method("handle_hover"):
|
||||
parent = parent.get_parent()
|
||||
return parent
|
||||
|
||||
## === DRAG LIFECYCLE METHODS ===
|
||||
## Override these in Card and StickyNote for specific behavior
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
prints("Draggable[base]._on_mouse_entered", self, self.name)
|
||||
mouse_over = true
|
||||
var handler := _get_hover_handler()
|
||||
if handler: handler.handle_hover(self)
|
||||
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
prints("Draggable[base]._on_mouse_exited", self, self.name)
|
||||
mouse_over = false
|
||||
var handler := _get_hover_handler()
|
||||
if handler: handler.handle_hover(self)
|
||||
|
||||
|
||||
## Starts a drag operation
|
||||
func start_drag(mouse_offset: Vector2) -> void:
|
||||
_drag_start_position = global_position
|
||||
|
|
@ -60,9 +88,10 @@ func find_drop_target() -> Node:
|
|||
return get_parent()
|
||||
|
||||
## Called after drop to clean up drag state
|
||||
func end_drag() -> void:
|
||||
func end_drag() -> Node:
|
||||
is_dragged = false
|
||||
_drag_source = null
|
||||
return null
|
||||
|
||||
|
||||
## Confines this draggable element to stay within screen or container bounds
|
||||
|
|
@ -100,11 +129,3 @@ func _get_container_bounds() -> Rect2:
|
|||
viewport_size.x - screen_margin * 2,
|
||||
viewport_size.y - screen_margin * 2
|
||||
)
|
||||
|
||||
|
||||
# === HELPERS ===
|
||||
## Static helper to check if a node implements DropTarget pattern
|
||||
## DropTarget pattern requires: can_accept_drop(draggable) and handle_drop(draggable)
|
||||
static func is_drop_target(node: Node) -> bool:
|
||||
return node != null and node.has_method("can_accept_drop") and node.has_method("handle_drop")
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,6 @@ _data = {
|
|||
}
|
||||
|
||||
[node name="board" type="PanelContainer"]
|
||||
z_index = -100
|
||||
material = SubResource("ShaderMaterial_ttqei")
|
||||
clip_contents = true
|
||||
anchors_preset = 15
|
||||
|
|
@ -175,6 +174,7 @@ mouse_filter = 1
|
|||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(400, 0)
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
|
||||
[node name="instructions_panel" type="PanelContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
|
|
|||
|
|
@ -45,24 +45,19 @@ func set_highlight(value: bool) -> void:
|
|||
if value != _highlighted:
|
||||
_highlighted = value
|
||||
|
||||
if is_inside_tree() and is_node_ready():
|
||||
if modulate_tween: modulate_tween.kill()
|
||||
if shift_tween: shift_tween.kill()
|
||||
if _highlighted:
|
||||
modulate_tween = get_tree().create_tween()
|
||||
modulate_tween.tween_property(self, "modulate", highlight_color, 0.1)
|
||||
shift_tween = get_tree().create_tween()
|
||||
shift_tween.tween_property(content, "position", shift_by, 0.2)
|
||||
else:
|
||||
modulate_tween = get_tree().create_tween()
|
||||
modulate_tween.tween_property(self, "modulate", Color(1, 1, 1), 0.3)
|
||||
shift_tween = get_tree().create_tween()
|
||||
shift_tween.tween_property(content, "position", Vector2.ZERO, 0.5)
|
||||
if modulate_tween: modulate_tween.kill()
|
||||
if shift_tween: shift_tween.kill()
|
||||
|
||||
if _highlighted:
|
||||
modulate_tween = create_tween()
|
||||
modulate_tween.tween_property(self, "modulate", highlight_color, 0.1)
|
||||
shift_tween = create_tween()
|
||||
shift_tween.tween_property(content, "position", shift_by, 0.2)
|
||||
else:
|
||||
if _highlighted:
|
||||
modulate = Color(1, 1, 1)
|
||||
else:
|
||||
modulate = Color(1, 1, 1)
|
||||
modulate_tween = create_tween()
|
||||
modulate_tween.tween_property(self, "modulate", Color(1, 1, 1), 0.3)
|
||||
shift_tween = create_tween()
|
||||
shift_tween.tween_property(content, "position", Vector2.ZERO, 0.5)
|
||||
|
||||
@export var voice_line: AudioStream = null
|
||||
@export var is_dragable: bool = false
|
||||
|
|
@ -86,19 +81,13 @@ func init(sticky_name: String = "sticky_note", card_id: StringName = "-1") -> vo
|
|||
sticky_id = card_id
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
label = $Content/Label
|
||||
background_sprite = $Content/BackgroundSprite
|
||||
content = $Content
|
||||
|
||||
_on_text_updated.call_deferred()
|
||||
|
||||
input_event.connect(_on_input_event)
|
||||
mouse_entered.connect(_on_mouse_entered)
|
||||
mouse_exited.connect(_on_mouse_exited)
|
||||
area_entered.connect(_on_area_enter)
|
||||
area_exited.connect(_on_area_exit)
|
||||
|
||||
|
||||
|
||||
func _on_text_updated():
|
||||
label.text = text
|
||||
|
|
@ -108,29 +97,6 @@ func _on_text_updated():
|
|||
func _process(delta: float) -> void:
|
||||
_move_sticky_note(delta)
|
||||
|
||||
func _on_mouse_entered():
|
||||
if not Input.is_action_pressed("mouse_left") and current_handle and current_handle.has_method("handle_hover"):
|
||||
current_handle.handle_hover(self)
|
||||
|
||||
func _on_mouse_exited():
|
||||
highlighted = false
|
||||
|
||||
# Let parent card re-check hover state if this sticky is attached to it
|
||||
var card := attached_to
|
||||
if card:
|
||||
card.check_hover()
|
||||
|
||||
func _on_area_enter(_area: Area2D):
|
||||
pass
|
||||
|
||||
func _on_area_exit(_area: Area2D):
|
||||
pass
|
||||
|
||||
func _on_input_event(_viewport, event, _shape_idx):
|
||||
if event is InputEventMouseButton and current_handle and current_handle.has_method("handle_mouse_button"):
|
||||
if (event.button_index == MOUSE_BUTTON_LEFT and event.pressed) or event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
mouse_offset = get_viewport().get_mouse_position() - global_position
|
||||
current_handle.handle_mouse_button(event, self)
|
||||
|
||||
## frame rate independent FIR smoothing filter
|
||||
func _smooth(current: Vector2, goal: Vector2, delta: float) -> Vector2:
|
||||
|
|
@ -171,31 +137,25 @@ func tween_transform_to(target: Transform2D, duration: float = 0.25) ->void:
|
|||
|
||||
# === DRAG LIFECYCLE OVERRIDES ===
|
||||
|
||||
## Start drag: if in panel, immediately move to board
|
||||
func start_drag(offset: Vector2) -> void:
|
||||
super.start_drag(offset)
|
||||
|
||||
# If attached to a card, detach it first
|
||||
var card := attached_to
|
||||
if card:
|
||||
card.remove_sticky_note()
|
||||
func end_drag() -> Node:
|
||||
super.end_drag()
|
||||
return _find_drop_target()
|
||||
|
||||
|
||||
## Find best drop target: Card > Panel > Board (in priority order)
|
||||
func find_drop_target() -> Node:
|
||||
func _find_drop_target() -> Node:
|
||||
# Priority 1: Check for overlapping cards in dropzone
|
||||
var closest : Card = null
|
||||
for area in get_overlapping_areas():
|
||||
if area is Card and Draggable.is_drop_target(area):
|
||||
if area is StickyNote and not area.is_attached: continue # Can only drop on attached stickies
|
||||
|
||||
if area is Card:
|
||||
if (not closest) or ((closest.position-position).length() < (area.position - position).length()):
|
||||
closest = area
|
||||
return area
|
||||
|
||||
# Priority 2: Check if dropped outside dropzone (over panel area)
|
||||
if current_handle and not current_handle.is_in_dropzone(self):
|
||||
var target_panel := _find_nearest_panel()
|
||||
if target_panel:
|
||||
return target_panel
|
||||
|
||||
# Priority 3: Default to board (stay loose in dropzone)
|
||||
return current_handle
|
||||
return null
|
||||
|
||||
## Find the nearest panel that can accept this sticky
|
||||
func _find_nearest_panel() -> StickyNotePanel:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ radius = 48.0
|
|||
height = 312.0
|
||||
|
||||
[node name="sticky-note" type="Area2D"]
|
||||
z_index = 1
|
||||
collision_layer = 2
|
||||
collision_mask = 6
|
||||
priority = 100
|
||||
|
|
|
|||
|
|
@ -4,3 +4,6 @@ class_name Playable
|
|||
## Awaitable that encapsulates the core interaction with this Playable
|
||||
func play() -> void:
|
||||
await get_tree().process_frame # Dummy wait so this is a coroutine
|
||||
|
||||
func handle_hover(area: Draggable):
|
||||
prints("Playable[base].handle_hover", area, area.name)
|
||||
|
|
|
|||
Loading…
Reference in New Issue