Compare commits
No commits in common. "6e94ccc1344fa181b5e80ec85215ba577a28fd13" and "971c1622368f18e1d999d742d021b383b4b22fd1" have entirely different histories.
6e94ccc134
...
971c162236
|
|
@ -137,11 +137,6 @@ func _on_board_focused() -> void:
|
|||
visible = true
|
||||
if is_node_ready():
|
||||
process_mode = Node.PROCESS_MODE_INHERIT
|
||||
|
||||
# Check board state and give lore feedback when presented
|
||||
if is_board_complete():
|
||||
board_was_completed = true
|
||||
give_lore_feedback()
|
||||
|
||||
|
||||
## Called when board loses focus
|
||||
|
|
@ -209,99 +204,91 @@ func is_in_dropzone(to_check: Node) -> bool:
|
|||
|
||||
# Called by notes when a mouse event needs handling
|
||||
func handle_mouse_button(input: InputEventMouseButton, to_handle = currently_active_node) -> void:
|
||||
# Prevent dragging multiple nodes at once
|
||||
|
||||
# Makes sure that only the same area is dragged.
|
||||
# Otherwise overlapping areas are dragged at the same time.
|
||||
if current_context == DRAG and to_handle != currently_active_node:
|
||||
return
|
||||
|
||||
# === DRAG START ===
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and input.pressed:
|
||||
_start_drag(to_handle)
|
||||
return
|
||||
|
||||
# === DRAG END ===
|
||||
if input.button_index == MOUSE_BUTTON_LEFT and not input.pressed:
|
||||
_end_drag(to_handle)
|
||||
return
|
||||
|
||||
if input.button_index == MOUSE_BUTTON_MASK_LEFT and input.pressed:
|
||||
currently_active_node = to_handle
|
||||
to_handle.is_dragged = true
|
||||
if to_handle is StickyNote:
|
||||
if not to_handle.on_board:
|
||||
to_handle.reparent(dropzone)
|
||||
to_handle.on_board = true
|
||||
to_handle.attached_to = self
|
||||
current_context = DRAG
|
||||
|
||||
|
||||
## Starts a drag operation for the given draggable
|
||||
func _start_drag(draggable: Draggable) -> void:
|
||||
currently_active_node = draggable
|
||||
current_context = DRAG
|
||||
|
||||
var mouse_offset = get_viewport().get_mouse_position() - draggable.global_position
|
||||
draggable.start_drag(mouse_offset)
|
||||
# when Drag stops ...
|
||||
if input.button_index == MOUSE_BUTTON_MASK_LEFT and not input.pressed:
|
||||
to_handle.is_dragged = false
|
||||
if to_handle is StickyNote:
|
||||
if is_in_dropzone(to_handle):
|
||||
if to_handle.has_overlapping_areas():
|
||||
for area in to_handle.get_overlapping_areas():
|
||||
if area is Card:
|
||||
focus_stickies = false
|
||||
if area.has_sticky_note_attached():
|
||||
to_handle = area.exchange_sticky_note_with(to_handle)
|
||||
to_handle.reparent(dropzone)
|
||||
to_handle.on_board = true
|
||||
if sticky_note_container.get_child_count() > 0:
|
||||
sticky_note_container.get_child(current_sticky_note_id).attached_sticky_note = to_handle
|
||||
to_handle.attached_to = sticky_note_container.get_child(current_sticky_note_id)
|
||||
else:
|
||||
var new_panel = StickyNotePanel.new()
|
||||
sticky_note_container.add_child(new_panel, true, Node.INTERNAL_MODE_DISABLED)
|
||||
new_panel.owner = self
|
||||
new_panel.attatch_sticky_note(to_handle, self, false)
|
||||
current_sticky_note_id = 0
|
||||
to_handle.reset_drag()
|
||||
current_context = NAVIGATE
|
||||
_return_sticky_notes_to_panels()
|
||||
return
|
||||
else:
|
||||
area.attach_sticky_note(to_handle)
|
||||
to_handle.z_index = 0
|
||||
if sticky_note_container.get_child_count() > 0:
|
||||
sticky_note_container.get_child(current_sticky_note_id).clear_if_empty()
|
||||
current_context = NAVIGATE
|
||||
check_board_comnpletion()
|
||||
return
|
||||
else:
|
||||
var i: int = 0
|
||||
for panel: StickyNotePanel in sticky_note_container.get_children():
|
||||
i += 1
|
||||
if panel.is_empty:
|
||||
if panel.get_global_rect().intersects(Rect2(to_handle.global_position - Vector2(to_handle.diameter/2, 10), Vector2(to_handle.diameter/2, 10))):
|
||||
panel.attatch_sticky_note(to_handle, self)
|
||||
elif panel.is_gapped or i == sticky_note_container.get_child_count():
|
||||
panel.collapse_gap()
|
||||
var new_panel = StickyNotePanel.new()
|
||||
sticky_note_container.add_child(new_panel)
|
||||
sticky_note_container.move_child(new_panel, i)
|
||||
new_panel.attatch_sticky_note(to_handle, self)
|
||||
new_panel.owner = self
|
||||
panel.clear_if_empty()
|
||||
_return_sticky_notes_to_panels()
|
||||
current_context = NAVIGATE
|
||||
return
|
||||
|
||||
|
||||
## Ends a drag operation and handles the drop
|
||||
func _end_drag(draggable: Draggable) -> void:
|
||||
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)
|
||||
|
||||
# Handle exchange result (sticky swapped with card's sticky)
|
||||
if result == Draggable.DropResult.EXCHANGED:
|
||||
_handle_sticky_exchange(draggable, drop_target)
|
||||
elif draggable is StickyNote and not is_in_dropzone(draggable):
|
||||
# Sticky dropped in panel area but no empty panel found - create one
|
||||
add_sticky_note(draggable)
|
||||
else:
|
||||
# Fallback: use default board drop
|
||||
handle_drop(draggable)
|
||||
|
||||
# Cleanup and state update
|
||||
_return_sticky_notes_to_panels()
|
||||
current_context = NAVIGATE
|
||||
_update_focus_after_drop(draggable)
|
||||
|
||||
# Check win condition if sticky was attached to card
|
||||
if draggable is StickyNote and draggable.is_sticky_note_attached():
|
||||
check_board_comnpletion()
|
||||
|
||||
|
||||
## Handles the exchange when a sticky is dropped on a card that already has one
|
||||
## The exchanged sticky always goes to the sticky_note_container (panel zone)
|
||||
func _handle_sticky_exchange(new_sticky: StickyNote, card: Card) -> void:
|
||||
var old_sticky = card.get_last_exchanged_sticky()
|
||||
|
||||
if not old_sticky:
|
||||
push_warning("CardBoard: Exchange occurred but no sticky returned")
|
||||
return
|
||||
|
||||
# Reset visual state for old sticky
|
||||
old_sticky.rotation = old_sticky.base_rotation
|
||||
old_sticky.scale = old_sticky.base_scale
|
||||
old_sticky.z_index = 0
|
||||
|
||||
# Exchanged sticky always goes to sticky_note_container
|
||||
if new_sticky._came_from_panel and sticky_note_container.get_child_count() > 0:
|
||||
# New sticky came from panel - return old sticky to that panel (swap positions)
|
||||
var target_panel = sticky_note_container.get_child(current_sticky_note_id)
|
||||
old_sticky.reparent(dropzone)
|
||||
old_sticky.on_board = true
|
||||
target_panel.attached_sticky_note = old_sticky
|
||||
old_sticky.attached_to = target_panel
|
||||
target_panel.attatch_sticky_note(old_sticky, self, false, true)
|
||||
else:
|
||||
# New sticky was loose - create new panel for old sticky
|
||||
add_sticky_note(old_sticky)
|
||||
|
||||
# Clean up empty panel if the new sticky came from one
|
||||
if new_sticky._came_from_panel and sticky_note_container.get_child_count() > 0:
|
||||
sticky_note_container.get_child(current_sticky_note_id).clear_if_empty()
|
||||
|
||||
|
||||
## Updates focus and navigation state after a drop
|
||||
func _update_focus_after_drop(draggable: Draggable) -> void:
|
||||
# Update focus based on where the item ended up
|
||||
if draggable is Card or (draggable is StickyNote and draggable.on_board):
|
||||
## Dropping Cards and Sticky Notes not causing a return condition above.
|
||||
if not (to_handle is StickyNote and to_handle.is_sticky_note_attached()):
|
||||
if to_handle.get_parent() is Card:
|
||||
insert_area(to_handle.get_parent().remove_sticky_note(), to_handle)
|
||||
else:
|
||||
insert_area(dropzone, to_handle)
|
||||
current_context = NAVIGATE
|
||||
focus_stickies = false
|
||||
current_dropzone_id = dropzone.get_children().find(draggable)
|
||||
current_dropzone_id = dropzone.get_children().find(to_handle)
|
||||
if to_handle is StickyNote:
|
||||
to_handle.rotation = to_handle.base_rotation
|
||||
to_handle.scale = to_handle.base_scale
|
||||
|
||||
if input.is_action_pressed("mouse_right") and current_context == DRAG:
|
||||
to_handle.reset_drag()
|
||||
|
||||
|
||||
func _return_sticky_notes_to_panels() -> void:
|
||||
|
|
@ -392,7 +379,7 @@ func insert_area(parent: Control, node: Area2D):
|
|||
var i = 0
|
||||
|
||||
if not node in parent.get_children():
|
||||
node.reparent(parent, false) # Don't preserve global transform - we set positions explicitly
|
||||
node.reparent(parent)
|
||||
if node is StickyNote:
|
||||
node.on_board = true
|
||||
node.owner = self
|
||||
|
|
@ -407,65 +394,6 @@ func insert_area(parent: Control, node: Area2D):
|
|||
node.attached_to = self
|
||||
node.is_dragable = true
|
||||
|
||||
## Sorts all children in dropzone by their Y position
|
||||
## Call this after bulk loading to fix child order / z-index issues
|
||||
func _sort_dropzone_children() -> void:
|
||||
var children = dropzone.get_children()
|
||||
if children.size() <= 1:
|
||||
return
|
||||
|
||||
# Sort by global Y position
|
||||
children.sort_custom(func(a, b): return a.global_position.y < b.global_position.y)
|
||||
|
||||
# Reorder children in the scene tree
|
||||
for i in range(children.size()):
|
||||
dropzone.move_child(children[i], i)
|
||||
|
||||
print_debug("CardBoard: Re-sorted %d dropzone children by Y position" % children.size())
|
||||
|
||||
# Force collision shape updates on next physics frame
|
||||
# This ensures Area2D hover detection works correctly after repositioning
|
||||
_update_collision_shapes.call_deferred()
|
||||
|
||||
## Forces collision shape updates for all cards/stickies in dropzone
|
||||
func _update_collision_shapes() -> void:
|
||||
await get_tree().process_frame
|
||||
for child in dropzone.get_children():
|
||||
if child is Area2D:
|
||||
# Force collision shape update by toggling monitoring
|
||||
var was_monitoring = child.monitoring
|
||||
child.monitoring = false
|
||||
child.monitoring = was_monitoring
|
||||
|
||||
# === DROP TARGET PATTERN IMPLEMENTATION ===
|
||||
|
||||
## Checks if this board can accept the given draggable (always true for board)
|
||||
func can_accept_drop(draggable: Draggable) -> bool:
|
||||
return draggable is Card or draggable is StickyNote
|
||||
|
||||
## Handles dropping a draggable onto the board (into the dropzone)
|
||||
func handle_drop(draggable: Draggable) -> int:
|
||||
if not can_accept_drop(draggable):
|
||||
return Draggable.DropResult.REJECTED
|
||||
|
||||
if draggable is StickyNote:
|
||||
# Handle sticky note drop
|
||||
var sticky = draggable as StickyNote
|
||||
insert_area(dropzone, sticky)
|
||||
sticky.attached_to = self
|
||||
sticky.on_board = true
|
||||
sticky.is_dragable = true
|
||||
# Reset visual state
|
||||
sticky.rotation = sticky.base_rotation
|
||||
sticky.scale = sticky.base_scale
|
||||
elif draggable is Card:
|
||||
# Handle card drop
|
||||
insert_area(dropzone, draggable)
|
||||
draggable.is_dragable = true
|
||||
|
||||
return Draggable.DropResult.ACCEPTED
|
||||
|
||||
|
||||
# Takes the inputs for control inputs
|
||||
func _input(event) -> void:
|
||||
|
||||
|
|
@ -702,25 +630,21 @@ func initialise_from_save(savegame: SaveGame) -> void:
|
|||
# Add all cards
|
||||
print_debug(" Loading %d cards..." % card_pile["cards"].size())
|
||||
for card: Card in card_pile["cards"]:
|
||||
# Determine target position (will be set after adding to scene)
|
||||
var target_position: Vector2
|
||||
if savegame.board_positions.has(card.name):
|
||||
target_position = savegame.board_positions[card.name]
|
||||
print_debug(" Card '%s' loading at %s" % [card.name, target_position])
|
||||
else:
|
||||
target_position = _generate_random_position()
|
||||
print_debug(" Card '%s' - generated random position: %s" % [card.name, target_position])
|
||||
|
||||
# Add to board first
|
||||
add_child(card)
|
||||
insert_area(dropzone, card)
|
||||
|
||||
# Set position from save, or generate random if missing (must be after insert_area)
|
||||
if savegame.board_positions.has(card.name):
|
||||
card.position = savegame.board_positions[card.name]
|
||||
print_debug(" Card '%s' at %s" % [card.name, card.position])
|
||||
else:
|
||||
card.position = _generate_random_position()
|
||||
print_debug(" Card '%s' - generated random position: %s" % [card.name, card.position])
|
||||
|
||||
card.set_owner(self)
|
||||
card.is_dragable = true
|
||||
cards_by_name[card.name] = card
|
||||
card.picked_random = savegame.board_randoms.has(card.card_id)
|
||||
|
||||
# Move to dropzone and set position (position must be set after adding to scene)
|
||||
insert_area(dropzone, card)
|
||||
card.position = target_position
|
||||
|
||||
# Add all sticky notes
|
||||
print_debug(" Loading %d stickies..." % card_pile["sticky_notes"].size())
|
||||
|
|
@ -746,36 +670,26 @@ func initialise_from_save(savegame: SaveGame) -> void:
|
|||
|
||||
# Sticky is loose on board
|
||||
else:
|
||||
# Determine target position (will be set after adding to scene)
|
||||
var target_position: Vector2
|
||||
if savegame.board_positions.has(sticky.name):
|
||||
target_position = savegame.board_positions[sticky.name]
|
||||
print_debug(" Loose sticky '%s' loading at %s" % [sticky.name, target_position])
|
||||
else:
|
||||
target_position = _generate_random_position()
|
||||
print_debug(" Loose sticky '%s' - generated random position: %s" % [sticky.name, target_position])
|
||||
|
||||
# Add to board first
|
||||
add_child(sticky)
|
||||
insert_area(dropzone, sticky)
|
||||
|
||||
# Set position from save, or generate random if missing (must be after insert_area)
|
||||
if savegame.board_positions.has(sticky.name):
|
||||
sticky.position = savegame.board_positions[sticky.name]
|
||||
print_debug(" Loose sticky '%s' at %s" % [sticky.name, sticky.position])
|
||||
else:
|
||||
sticky.position = _generate_random_position()
|
||||
print_debug(" Loose sticky '%s' - generated random position: %s" % [sticky.name, sticky.position])
|
||||
|
||||
sticky.set_owner(self)
|
||||
sticky.current_handle = self # Required for input handling
|
||||
sticky.on_board = true
|
||||
sticky.attached_to = self
|
||||
sticky.is_dragable = true
|
||||
|
||||
# Move to dropzone and set position (position must be set after adding to scene)
|
||||
insert_area(dropzone, sticky)
|
||||
sticky.position = target_position
|
||||
|
||||
sticky.picked_random = savegame.board_randoms.has(sticky.sticky_id)
|
||||
|
||||
print_debug("CardBoard: Load complete!")
|
||||
|
||||
# Re-sort dropzone children now that all positions are set correctly
|
||||
# This fixes hover detection issues caused by incorrect z-order during load
|
||||
_sort_dropzone_children()
|
||||
|
||||
# Note: Lore feedback will be triggered when board is presented (in play())
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,8 @@ func _on_input_event(_viewport, event, _shape_idx):
|
|||
|
||||
func _move_card():
|
||||
if is_dragged:
|
||||
update_drag_position(get_viewport().get_mouse_position())
|
||||
position = get_viewport().get_mouse_position() - mouse_offset
|
||||
confine_to_screen()
|
||||
|
||||
func has_sticky_note_attached() -> bool:
|
||||
return get_attached_sticky_note() != null
|
||||
|
|
@ -295,49 +296,3 @@ func reclaim_sticky_note():
|
|||
await current_sticky_note.transform_tween_finished
|
||||
current_sticky_note.reparent(self)
|
||||
current_sticky_note.owner = self.owner
|
||||
|
||||
|
||||
# === DROP TARGET PATTERN IMPLEMENTATION ===
|
||||
|
||||
## Temporary storage for exchanged sticky during drop operation
|
||||
var _last_exchanged_sticky: StickyNote = null
|
||||
|
||||
## Checks if this card can accept the given draggable
|
||||
func can_accept_drop(draggable: Draggable) -> bool:
|
||||
return draggable is StickyNote
|
||||
|
||||
## Handles dropping a sticky note onto this card
|
||||
## Returns DropResult indicating success, rejection, or exchange
|
||||
func handle_drop(draggable: StickyNote) -> int:
|
||||
if not can_accept_drop(draggable):
|
||||
return Draggable.DropResult.REJECTED
|
||||
|
||||
if has_sticky_note_attached():
|
||||
# Exchange: remove current, attach new, store old for retrieval
|
||||
_last_exchanged_sticky = exchange_sticky_note_with(draggable)
|
||||
# Reset z_index for newly attached sticky
|
||||
draggable.z_index = 0
|
||||
return Draggable.DropResult.EXCHANGED
|
||||
else:
|
||||
# Simple attach
|
||||
if attach_sticky_note(draggable):
|
||||
# Reset z_index for newly attached sticky
|
||||
draggable.z_index = 0
|
||||
return Draggable.DropResult.ACCEPTED
|
||||
else:
|
||||
# Attach failed (shouldn't happen, but handle it)
|
||||
return Draggable.DropResult.REJECTED
|
||||
|
||||
## Retrieves the sticky that was exchanged during last drop
|
||||
## Clears the reference after retrieval
|
||||
func get_last_exchanged_sticky() -> StickyNote:
|
||||
var result = _last_exchanged_sticky
|
||||
_last_exchanged_sticky = null
|
||||
return result
|
||||
|
||||
|
||||
# === DRAG LIFECYCLE OVERRIDES ===
|
||||
|
||||
## Cards always drop back to board dropzone
|
||||
func find_drop_target() -> Node:
|
||||
return owner if owner is CardBoard else get_parent()
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ anchors_preset = 15
|
|||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -126.0
|
||||
offset_top = -100.0
|
||||
offset_top = -88.0
|
||||
offset_right = 136.0
|
||||
offset_bottom = 77.95834
|
||||
offset_bottom = 89.95834
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("3_mdi7r")
|
||||
|
|
|
|||
|
|
@ -4,18 +4,6 @@ extends Area2D
|
|||
## Base class for draggable UI elements (Cards and StickyNotes)
|
||||
## Provides common dragging behavior and boundary protection
|
||||
|
||||
## Drop result codes for DropTarget pattern
|
||||
enum DropResult {
|
||||
ACCEPTED, # Drop successful, item is now owned by target
|
||||
REJECTED, # Drop refused, item stays with previous owner
|
||||
EXCHANGED # Swap occurred, exchanged item needs handling
|
||||
}
|
||||
|
||||
## 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")
|
||||
|
||||
var is_dragged: bool = false:
|
||||
set(dragged):
|
||||
is_dragged = dragged
|
||||
|
|
@ -24,38 +12,6 @@ var is_dragged: bool = false:
|
|||
## Margin from screen edges when confining to screen bounds
|
||||
@export var screen_margin: float = 50.0
|
||||
|
||||
## Drag state tracking
|
||||
var _drag_start_position: Vector2
|
||||
var _mouse_drag_offset: Vector2
|
||||
var _drag_source: Node = null # Where the drag started from
|
||||
|
||||
## === DRAG LIFECYCLE METHODS ===
|
||||
## Override these in Card and StickyNote for specific behavior
|
||||
|
||||
## Starts a drag operation
|
||||
func start_drag(mouse_offset: Vector2) -> void:
|
||||
_drag_start_position = global_position
|
||||
_mouse_drag_offset = mouse_offset
|
||||
_drag_source = get_parent()
|
||||
is_dragged = true
|
||||
|
||||
## Updates position during drag (call from _process or manual update)
|
||||
func update_drag_position(mouse_pos: Vector2) -> void:
|
||||
global_position = mouse_pos - _mouse_drag_offset
|
||||
confine_to_screen()
|
||||
|
||||
## Finds the best drop target for this draggable
|
||||
## Override in subclasses for specific drop target logic
|
||||
## Returns the node that should receive the drop, or null for no valid target
|
||||
func find_drop_target() -> Node:
|
||||
# Base implementation: return parent (board)
|
||||
return get_parent()
|
||||
|
||||
## Called after drop to clean up drag state
|
||||
func end_drag() -> void:
|
||||
is_dragged = false
|
||||
_drag_source = null
|
||||
|
||||
## Confines this draggable element to stay within screen or container bounds
|
||||
## Skip this check if a sticky note is attached to a card
|
||||
func confine_to_screen() -> void:
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ _data = {
|
|||
}
|
||||
|
||||
[node name="board" type="PanelContainer"]
|
||||
z_index = -100
|
||||
material = SubResource("ShaderMaterial_ttqei")
|
||||
clip_contents = true
|
||||
anchors_preset = 15
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ func _on_input_event(_viewport, event, _shape_idx):
|
|||
|
||||
func _move_sticky_note():
|
||||
if is_dragged:
|
||||
update_drag_position(get_viewport().get_mouse_position())
|
||||
global_position = get_viewport().get_mouse_position() - mouse_offset
|
||||
confine_to_screen()
|
||||
|
||||
func is_sticky_note_attached() -> bool:
|
||||
# FIXME: this breaks if attatched to is previousely freed because GODOT IS FUCKING STUPID
|
||||
|
|
@ -154,69 +155,3 @@ func tween_transform_to(target: Transform2D):
|
|||
await transform_tween.finished
|
||||
transform_tween_finished.emit()
|
||||
|
||||
|
||||
# === DRAG LIFECYCLE OVERRIDES ===
|
||||
|
||||
## Track whether this sticky came from a panel (for exchange logic)
|
||||
var _came_from_panel: bool = false
|
||||
|
||||
## Start drag: if in panel, immediately move to board
|
||||
func start_drag(offset: Vector2) -> void:
|
||||
super.start_drag(offset)
|
||||
_came_from_panel = is_sticky_note_in_panel()
|
||||
|
||||
# If attached to a card, detach it first
|
||||
if is_sticky_note_attached():
|
||||
var card := attached_to as Card
|
||||
if card and card.has_method("remove_sticky_note"):
|
||||
card.remove_sticky_note()
|
||||
|
||||
# If in panel, immediately reparent to board for dragging
|
||||
if _came_from_panel and current_handle:
|
||||
var board := current_handle
|
||||
var dropzone := board.get_node_or_null("HBoxContainer/dropzone")
|
||||
if dropzone:
|
||||
reparent(dropzone)
|
||||
else:
|
||||
reparent(board)
|
||||
on_board = true
|
||||
attached_to = board
|
||||
|
||||
## Find best drop target: Card > Panel > Board (in priority order)
|
||||
func find_drop_target() -> Node:
|
||||
# Priority 1: Check for overlapping cards in dropzone
|
||||
for area in get_overlapping_areas():
|
||||
if area is Card and Draggable.is_drop_target(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
|
||||
|
||||
## Find the nearest panel that can accept this sticky
|
||||
func _find_nearest_panel() -> StickyNotePanel:
|
||||
if not current_handle or not current_handle.has_node("HBoxContainer/ScrollContainer/VBoxContainer"):
|
||||
return null
|
||||
|
||||
var panel_container := current_handle.get_node("HBoxContainer/ScrollContainer/VBoxContainer")
|
||||
var sticky_rect := Rect2(global_position - Vector2(diameter/2, 10), Vector2(diameter/2, 10))
|
||||
|
||||
# First pass: look for empty panels we're hovering over
|
||||
for panel in panel_container.get_children():
|
||||
if panel is StickyNotePanel:
|
||||
if panel.is_empty() and panel.get_global_rect().intersects(sticky_rect):
|
||||
return panel
|
||||
|
||||
# Second pass: if no empty panel found, find first empty panel
|
||||
for panel in panel_container.get_children():
|
||||
if panel is StickyNotePanel and panel.is_empty():
|
||||
return panel
|
||||
|
||||
# No empty panels found - will need to create one (handled by board)
|
||||
return null
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ radius = 48.0
|
|||
height = 312.0
|
||||
|
||||
[node name="sticky-note" type="Area2D"]
|
||||
z_index = 1
|
||||
priority = 100
|
||||
script = ExtResource("1_yvh5n")
|
||||
text = "card"
|
||||
|
|
|
|||
|
|
@ -100,25 +100,3 @@ func replace_sticky_note_with(new_sticky_note: StickyNote):
|
|||
|
||||
func is_empty() -> bool:
|
||||
return get_child_count() == 0 and not is_attatching
|
||||
|
||||
|
||||
# === DROP TARGET PATTERN IMPLEMENTATION ===
|
||||
|
||||
## Checks if this panel can accept the given draggable
|
||||
func can_accept_drop(draggable: Draggable) -> bool:
|
||||
return draggable is StickyNote and is_empty()
|
||||
|
||||
## Handles dropping a sticky note onto this panel
|
||||
func handle_drop(draggable: StickyNote) -> int:
|
||||
if not can_accept_drop(draggable):
|
||||
return Draggable.DropResult.REJECTED
|
||||
|
||||
# Attach sticky to this panel
|
||||
attatch_sticky_note(draggable, owner, true, true)
|
||||
|
||||
# Clean up other empty panels
|
||||
for panel in get_parent().get_children():
|
||||
if panel is StickyNotePanel and panel != self:
|
||||
panel.clear_if_empty()
|
||||
|
||||
return Draggable.DropResult.ACCEPTED
|
||||
|
|
|
|||
|
|
@ -22,31 +22,25 @@ func _apply_enabled_state() -> void:
|
|||
jitter_tween.tween_property(self, "jitter_strength", 1.0, 1.0)
|
||||
if has_entered:
|
||||
ui_exited.emit()
|
||||
# Show hand cursor when player is enabled
|
||||
if hand_cursor:
|
||||
hand_cursor.visible = true
|
||||
else:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
jitter_tween = create_tween()
|
||||
jitter_tween.tween_property(self, "jitter_strength", 0.0, 0.5)
|
||||
if has_entered:
|
||||
ui_exited.emit()
|
||||
# Hide hand cursor when player is disabled
|
||||
if hand_cursor:
|
||||
hand_cursor.visible = false
|
||||
sleeping = not enabled
|
||||
|
||||
@export var mouse_sensitivity: Vector2 = Vector2(6, 5)
|
||||
|
||||
@export var initial_pitch: float = 50
|
||||
|
||||
@export_range (0.0, 10.0) var max_speed: float = 3
|
||||
@export_range (0.0, 10.0) var max_acceleration: float = 5
|
||||
@export_range (0.0, 20.0) var damp: float = 10
|
||||
@export_range (0.1, 1.0) var mouse_jerk:float = 0.5
|
||||
@export_range (10.0, 100.0) var gamepad_response:float = 50.0
|
||||
@export_range (50.0, 500.0) var mouse_jerk_rejection:float = 200.0
|
||||
@export var max_angle:float = 75.0
|
||||
@export_range (0, 10) var max_speed: float = 3
|
||||
@export_range (0, 10) var max_acceleration: float = 5
|
||||
@export_range (0, 20) var damp: float = 10
|
||||
@export_range (0.1, 1) var mouse_jerk:float = 0.5
|
||||
@export_range (10, 100) var gamepad_response:float = 50.0
|
||||
@export_range (50, 500) var mouse_jerk_rejection:float = 200.0
|
||||
@export var max_angle:float = 75
|
||||
|
||||
@export var camera_jitter_speed:float = 3
|
||||
@export var angular_jitter:Vector3 = Vector3(0.1, 0, 0.05)
|
||||
|
|
@ -93,11 +87,6 @@ var crouched:bool = false:
|
|||
@onready var camera: Camera3D = $Yaw/Pitch/Mount/Camera3D
|
||||
@onready var focus_ray: RayCast3D = $Yaw/Pitch/Mount/Camera3D/RayCast3D
|
||||
@onready var ui_prober: Area3D = $Yaw/Pitch/Mount/Camera3D/UiProber
|
||||
@onready var hand_cursor: TextureRect = %Cursor
|
||||
|
||||
# Cursor textures (preloaded for performance)
|
||||
const cursor_default: Texture2D = preload("res://import/interface-elements/cursor_point.png")
|
||||
const cursor_point: Texture2D = preload("res://import/interface-elements/cursor_grab.png")
|
||||
|
||||
@onready var base_fov := camera.fov
|
||||
var zoomed:bool = false:
|
||||
|
|
@ -127,9 +116,6 @@ func _ready():
|
|||
$CrouchDetector.area_entered.connect(enter_crouch)
|
||||
$CrouchDetector.area_exited.connect(exit_crouch)
|
||||
|
||||
# Setup hand cursor
|
||||
_setup_hand_cursor()
|
||||
|
||||
# Connect to central player enable signal.
|
||||
# Guard for standalone test scenes without autoloads.
|
||||
if get_node_or_null("/root/Scenes"):
|
||||
|
|
@ -142,12 +128,6 @@ func _ready():
|
|||
func _on_player_enable(enable: bool) -> void:
|
||||
enabled = enable
|
||||
|
||||
## Setup the hand cursor in the center of the screen
|
||||
func _setup_hand_cursor() -> void:
|
||||
# Configure the existing TextureRect for cursor display
|
||||
hand_cursor.texture = cursor_default # Start with default cursor
|
||||
hand_cursor.visible = false
|
||||
|
||||
## Restores player position and camera rotation from save game
|
||||
func restore_from_save(save: SaveGame) -> void:
|
||||
if save.player_position != Vector3.ZERO:
|
||||
|
|
@ -182,17 +162,11 @@ func _on_ray_entered(_area):
|
|||
assert(parent != null, "Ray entered non-interactable area!")
|
||||
printt("ray entered", parent.name, parent)
|
||||
parent.hover = true
|
||||
# Switch to pointing hand cursor when hovering over interactable
|
||||
if hand_cursor:
|
||||
hand_cursor.texture = cursor_point
|
||||
|
||||
func _on_ray_exited(_area):
|
||||
var parent := _area.get_parent() as Interactable
|
||||
printt("ray exited", parent.name, parent)
|
||||
parent.hover = false
|
||||
# Switch back to default cursor when not hovering
|
||||
if hand_cursor:
|
||||
hand_cursor.texture = cursor_default
|
||||
|
||||
|
||||
func _physics_process(delta: float):
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
[gd_scene load_steps=17 format=3 uid="uid://mkccbig41bqb"]
|
||||
[gd_scene load_steps=16 format=3 uid="uid://mkccbig41bqb"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bk618uyhghswx" path="res://logic-scenes/player_controller/player_controller.gd" id="1_0b4mi"]
|
||||
[ext_resource type="Texture2D" uid="uid://d005qvnbnishb" path="res://import/interface-elements/cursor_grab.png" id="2_x6v75"]
|
||||
|
||||
[sub_resource type="PhysicsMaterial" id="10"]
|
||||
friction = 0.0
|
||||
|
|
@ -658,23 +657,6 @@ mouse_filter = 2
|
|||
texture = SubResource("GradientTexture2D_x6v75")
|
||||
expand_mode = 4
|
||||
|
||||
[node name="Cursor" type="TextureRect" parent="Yaw/Pitch/Mount/Camera3D"]
|
||||
unique_name_in_owner = true
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
texture = ExtResource("2_x6v75")
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="PlayerCollision" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0.6, 0)
|
||||
shape = SubResource("CapsuleShape3D_hpoj0")
|
||||
|
|
|
|||
|
|
@ -58,16 +58,6 @@ func _sort_saves() -> void:
|
|||
return a.last_saved > b.last_saved
|
||||
)
|
||||
|
||||
func _get_slot_number(save: SaveGame) -> int:
|
||||
# Create a list sorted by file name (creation order) to determine slot numbers
|
||||
var saves_by_creation := saves.duplicate()
|
||||
saves_by_creation.sort_custom(func(a: SaveGame, b: SaveGame) -> int:
|
||||
return a.file_name < b.file_name # Older files first (ascending)
|
||||
)
|
||||
|
||||
# Find this save's position in the creation-order list
|
||||
return saves_by_creation.find(save) + 1
|
||||
|
||||
func _rebuild_buttons() -> void:
|
||||
save_buttons = []
|
||||
for child in list_container.get_children():
|
||||
|
|
@ -78,8 +68,7 @@ func _rebuild_buttons() -> void:
|
|||
list_container.add_child(save_box)
|
||||
|
||||
for i in range(saves.size()):
|
||||
var slot_number := _get_slot_number(saves[i])
|
||||
var new_button := SaveGameDisplay.new(saves[i], slot_number)
|
||||
var new_button := SaveGameDisplay.new(saves[i], i+1)
|
||||
save_box.add_child(new_button)
|
||||
save_buttons.append(new_button)
|
||||
new_button.pressed.connect(_on_game_picked.bind(i))
|
||||
|
|
|
|||
Loading…
Reference in New Issue