init
This commit is contained in:
253
addons/card-framework/drop_zone.gd
Normal file
253
addons/card-framework/drop_zone.gd
Normal file
@@ -0,0 +1,253 @@
|
||||
## Interactive drop zone system with sensor partitioning and visual debugging.
|
||||
##
|
||||
## DropZone provides sophisticated drag-and-drop target detection with configurable
|
||||
## sensor areas, partitioning systems, and visual debugging capabilities. It integrates
|
||||
## with CardContainer to enable precise card placement and reordering operations.
|
||||
##
|
||||
## Key Features:
|
||||
## - Flexible sensor sizing and positioning with dynamic adjustment
|
||||
## - Vertical/horizontal partitioning for precise drop targeting
|
||||
## - Visual debugging with colored outlines and partition indicators
|
||||
## - Mouse detection with global coordinate transformation
|
||||
## - Accept type filtering for specific draggable object types
|
||||
##
|
||||
## Partitioning System:
|
||||
## - Vertical partitions: Divide sensor into left-right sections for card ordering
|
||||
## - Horizontal partitions: Divide sensor into up-down sections for layered placement
|
||||
## - Dynamic outline generation for visual feedback during development
|
||||
##
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## var drop_zone = DropZone.new()
|
||||
## drop_zone.init(container, ["card"])
|
||||
## drop_zone.set_sensor(Vector2(200, 300), Vector2.ZERO, null, false)
|
||||
## drop_zone.set_vertical_partitions([100, 200, 300])
|
||||
## [/codeblock]
|
||||
class_name DropZone
|
||||
extends Control
|
||||
|
||||
|
||||
|
||||
# Dynamic sensor properties with automatic UI synchronization
|
||||
## Size of the drop sensor area
|
||||
var sensor_size: Vector2:
|
||||
set(value):
|
||||
sensor.size = value
|
||||
sensor_outline.size = value
|
||||
|
||||
## Position offset of the drop sensor relative to DropZone
|
||||
var sensor_position: Vector2:
|
||||
set(value):
|
||||
sensor.position = value
|
||||
sensor_outline.position = value
|
||||
|
||||
## @deprecated: Since it was designed to debug the sensor, please use sensor_outline_visible instead.
|
||||
var sensor_texture : Texture:
|
||||
set(value):
|
||||
sensor.texture = value
|
||||
|
||||
## @deprecated: Since it was designed to debug the sensor, please use sensor_outline_visible instead.
|
||||
var sensor_visible := true:
|
||||
set(value):
|
||||
sensor.visible = value
|
||||
|
||||
## Controls visibility of debugging outlines for sensor and partitions
|
||||
var sensor_outline_visible := false:
|
||||
set(value):
|
||||
sensor_outline.visible = value
|
||||
for outline in sensor_partition_outlines:
|
||||
outline.visible = value
|
||||
|
||||
# Core drop zone configuration and state
|
||||
## Array of accepted draggable object types (e.g., ["card", "token"])
|
||||
var accept_types: Array = []
|
||||
## Original sensor size for restoration after dynamic changes
|
||||
var stored_sensor_size: Vector2
|
||||
## Original sensor position for restoration after dynamic changes
|
||||
var stored_sensor_position: Vector2
|
||||
## Parent container that owns this drop zone
|
||||
var parent: Node
|
||||
|
||||
# UI components
|
||||
## Main sensor control for hit detection (invisible)
|
||||
var sensor: Control
|
||||
## Debug outline for visual sensor boundary indication
|
||||
var sensor_outline: ReferenceRect
|
||||
## Array of partition outline controls for debugging
|
||||
var sensor_partition_outlines: Array = []
|
||||
|
||||
# Partitioning system for precise drop targeting
|
||||
## Global vertical lines to divide sensing partitions (left to right direction)
|
||||
var vertical_partition: Array
|
||||
## Global horizontal lines to divide sensing partitions (up to down direction)
|
||||
var horizontal_partition: Array
|
||||
|
||||
|
||||
## Initializes the drop zone with parent reference and accepted drag types.
|
||||
## Creates sensor and debugging UI components.
|
||||
## @param _parent: Container that owns this drop zone
|
||||
## @param accept_types: Array of draggable object types this zone accepts
|
||||
func init(_parent: Node, accept_types: Array =[]):
|
||||
parent = _parent
|
||||
self.accept_types = accept_types
|
||||
|
||||
# Create invisible sensor for hit detection
|
||||
if sensor == null:
|
||||
sensor = TextureRect.new()
|
||||
sensor.name = "Sensor"
|
||||
sensor.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
sensor.z_index = CardFrameworkSettings.VISUAL_SENSOR_Z_INDEX # Behind everything else
|
||||
add_child(sensor)
|
||||
|
||||
# Create debugging outline (initially hidden)
|
||||
if sensor_outline == null:
|
||||
sensor_outline = ReferenceRect.new()
|
||||
sensor_outline.editor_only = false
|
||||
sensor_outline.name = "SensorOutline"
|
||||
sensor_outline.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
sensor_outline.border_color = CardFrameworkSettings.DEBUG_OUTLINE_COLOR
|
||||
sensor_outline.z_index = CardFrameworkSettings.VISUAL_OUTLINE_Z_INDEX
|
||||
add_child(sensor_outline)
|
||||
|
||||
# Initialize default values
|
||||
stored_sensor_size = Vector2(0, 0)
|
||||
stored_sensor_position = Vector2(0, 0)
|
||||
vertical_partition = []
|
||||
horizontal_partition = []
|
||||
|
||||
|
||||
## Checks if the mouse cursor is currently within the drop zone sensor area.
|
||||
## @returns: True if mouse is inside the sensor bounds
|
||||
func check_mouse_is_in_drop_zone() -> bool:
|
||||
var mouse_position = get_global_mouse_position()
|
||||
var result = sensor.get_global_rect().has_point(mouse_position)
|
||||
return result
|
||||
|
||||
|
||||
## Configures the sensor with size, position, texture, and visibility settings.
|
||||
## Stores original values for later restoration.
|
||||
## @param _size: Size of the sensor area
|
||||
## @param _position: Position offset from DropZone origin
|
||||
## @param _texture: Optional texture for sensor visualization
|
||||
## @param _visible: Whether sensor texture is visible (deprecated)
|
||||
func set_sensor(_size: Vector2, _position: Vector2, _texture: Texture, _visible: bool):
|
||||
sensor_size = _size
|
||||
sensor_position = _position
|
||||
stored_sensor_size = _size
|
||||
stored_sensor_position = _position
|
||||
sensor_texture = _texture
|
||||
sensor_visible = _visible
|
||||
|
||||
|
||||
## Dynamically adjusts sensor size and position without affecting stored values.
|
||||
## Used for temporary sensor modifications that can be restored later.
|
||||
## @param _size: New temporary sensor size
|
||||
## @param _position: New temporary sensor position
|
||||
func set_sensor_size_flexibly(_size: Vector2, _position: Vector2):
|
||||
sensor_size = _size
|
||||
sensor_position = _position
|
||||
|
||||
|
||||
## Restores sensor to its original size and position from stored values.
|
||||
## Used to undo temporary modifications made by set_sensor_size_flexibly.
|
||||
func return_sensor_size():
|
||||
sensor_size = stored_sensor_size
|
||||
sensor_position = stored_sensor_position
|
||||
|
||||
|
||||
## Adjusts sensor position by adding an offset to the stored position.
|
||||
## @param offset: Vector2 offset to add to the original stored position
|
||||
func change_sensor_position_with_offset(offset: Vector2):
|
||||
sensor_position = stored_sensor_position + offset
|
||||
|
||||
|
||||
## Sets vertical partition lines for drop targeting and creates debug outlines.
|
||||
## Vertical partitions divide the sensor into left-right sections for card ordering.
|
||||
## @param positions: Array of global X coordinates for partition lines
|
||||
func set_vertical_partitions(positions: Array):
|
||||
vertical_partition = positions
|
||||
|
||||
# Clear existing partition outlines
|
||||
for outline in sensor_partition_outlines:
|
||||
outline.queue_free()
|
||||
sensor_partition_outlines.clear()
|
||||
|
||||
# Create debug outline for each partition
|
||||
for i in range(vertical_partition.size()):
|
||||
var outline = ReferenceRect.new()
|
||||
outline.editor_only = false
|
||||
outline.name = "VerticalPartition" + str(i)
|
||||
outline.z_index = CardFrameworkSettings.VISUAL_OUTLINE_Z_INDEX
|
||||
outline.border_color = CardFrameworkSettings.DEBUG_OUTLINE_COLOR
|
||||
outline.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
outline.size = Vector2(1, sensor.size.y) # Vertical line full height
|
||||
|
||||
# Convert global partition position to local coordinates
|
||||
var local_x = vertical_partition[i] - global_position.x
|
||||
outline.position = Vector2(local_x, sensor.position.y)
|
||||
outline.visible = sensor_outline.visible
|
||||
add_child(outline)
|
||||
sensor_partition_outlines.append(outline)
|
||||
|
||||
|
||||
func set_horizontal_partitions(positions: Array):
|
||||
horizontal_partition = positions
|
||||
# clear existing outlines
|
||||
for outline in sensor_partition_outlines:
|
||||
outline.queue_free()
|
||||
sensor_partition_outlines.clear()
|
||||
for i in range(horizontal_partition.size()):
|
||||
var outline = ReferenceRect.new()
|
||||
outline.editor_only = false
|
||||
outline.name = "HorizontalPartition" + str(i)
|
||||
outline.z_index = CardFrameworkSettings.VISUAL_OUTLINE_Z_INDEX
|
||||
outline.border_color = CardFrameworkSettings.DEBUG_OUTLINE_COLOR
|
||||
outline.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
outline.size = Vector2(sensor.size.x, 1)
|
||||
var local_y = horizontal_partition[i] - global_position.y
|
||||
outline.position = Vector2(sensor.position.x, local_y)
|
||||
outline.visible = sensor_outline.visible
|
||||
add_child(outline)
|
||||
sensor_partition_outlines.append(outline)
|
||||
|
||||
|
||||
## Determines which vertical partition the mouse is currently in.
|
||||
## Returns the partition index for precise drop targeting.
|
||||
## @returns: Partition index (0-based) or -1 if outside sensor or no partitions
|
||||
func get_vertical_layers() -> int:
|
||||
if not check_mouse_is_in_drop_zone():
|
||||
return -1
|
||||
|
||||
if vertical_partition == null or vertical_partition.is_empty():
|
||||
return -1
|
||||
|
||||
var mouse_position = get_global_mouse_position()
|
||||
|
||||
# Count how many partition lines the mouse has crossed
|
||||
var current_index := 0
|
||||
|
||||
for i in range(vertical_partition.size()):
|
||||
if mouse_position.x >= vertical_partition[i]:
|
||||
current_index += 1
|
||||
else:
|
||||
break
|
||||
return current_index
|
||||
|
||||
|
||||
func get_horizontal_layers() -> int:
|
||||
if not check_mouse_is_in_drop_zone():
|
||||
return -1
|
||||
|
||||
if horizontal_partition == null or horizontal_partition.is_empty():
|
||||
return -1
|
||||
|
||||
var mouse_position = get_global_mouse_position()
|
||||
|
||||
var current_index := 0
|
||||
|
||||
for i in range(horizontal_partition.size()):
|
||||
if mouse_position.y >= horizontal_partition[i]:
|
||||
current_index += 1
|
||||
else:
|
||||
break
|
||||
return current_index
|
||||
Reference in New Issue
Block a user