init
This commit is contained in:
141
addons/card-framework/pile.gd
Normal file
141
addons/card-framework/pile.gd
Normal file
@@ -0,0 +1,141 @@
|
||||
## A stacked card container with directional positioning and interaction controls.
|
||||
##
|
||||
## Pile provides a traditional card stack implementation where cards are arranged
|
||||
## in a specific direction with configurable spacing. It supports various interaction
|
||||
## modes from full movement to top-card-only access, making it suitable for deck
|
||||
## implementations, foundation piles, and discard stacks.
|
||||
##
|
||||
## Key Features:
|
||||
## - Directional stacking (up, down, left, right)
|
||||
## - Configurable stack display limits and spacing
|
||||
## - Flexible interaction controls (all cards, top only, none)
|
||||
## - Dynamic drop zone positioning following top card
|
||||
## - Visual depth management with z-index layering
|
||||
##
|
||||
## Common Use Cases:
|
||||
## - Foundation piles in Solitaire games
|
||||
## - Draw/discard decks with face-down cards
|
||||
## - Tableau piles with partial card access
|
||||
##
|
||||
## Usage:
|
||||
## [codeblock]
|
||||
## @onready var deck = $Deck
|
||||
## deck.layout = Pile.PileDirection.DOWN
|
||||
## deck.card_face_up = false
|
||||
## deck.restrict_to_top_card = true
|
||||
## [/codeblock]
|
||||
class_name Pile
|
||||
extends CardContainer
|
||||
|
||||
# Enums
|
||||
## Defines the stacking direction for cards in the pile.
|
||||
enum PileDirection {
|
||||
UP, ## Cards stack upward (negative Y direction)
|
||||
DOWN, ## Cards stack downward (positive Y direction)
|
||||
LEFT, ## Cards stack leftward (negative X direction)
|
||||
RIGHT ## Cards stack rightward (positive X direction)
|
||||
}
|
||||
|
||||
@export_group("pile_layout")
|
||||
## Distance between each card in the stack display
|
||||
@export var stack_display_gap := CardFrameworkSettings.LAYOUT_STACK_GAP
|
||||
## Maximum number of cards to visually display in the pile
|
||||
## Cards beyond this limit will be hidden under the visible stack
|
||||
@export var max_stack_display := CardFrameworkSettings.LAYOUT_MAX_STACK_DISPLAY
|
||||
## Whether cards in the pile show their front face (true) or back face (false)
|
||||
@export var card_face_up := true
|
||||
## Direction in which cards are stacked from the pile's base position
|
||||
@export var layout := PileDirection.UP
|
||||
|
||||
@export_group("pile_interaction")
|
||||
## Whether any card in the pile can be moved via drag-and-drop
|
||||
@export var allow_card_movement: bool = true
|
||||
## Restricts movement to only the top card (requires allow_card_movement = true)
|
||||
@export var restrict_to_top_card: bool = true
|
||||
## Whether drop zone follows the top card position (requires allow_card_movement = true)
|
||||
@export var align_drop_zone_with_top_card := true
|
||||
|
||||
|
||||
## Returns the top n cards from the pile without removing them.
|
||||
## Cards are returned in top-to-bottom order (most recent first).
|
||||
## @param n: Number of cards to retrieve from the top
|
||||
## @returns: Array of cards from the top of the pile (limited by available cards)
|
||||
func get_top_cards(n: int) -> Array:
|
||||
var arr_size = _held_cards.size()
|
||||
if n > arr_size:
|
||||
n = arr_size
|
||||
|
||||
var result = []
|
||||
|
||||
for i in range(n):
|
||||
result.append(_held_cards[arr_size - 1 - i])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
## Updates z-index values for all cards to maintain proper layering.
|
||||
## Pressed cards receive elevated z-index to appear above the pile.
|
||||
func _update_target_z_index() -> void:
|
||||
for i in range(_held_cards.size()):
|
||||
var card = _held_cards[i]
|
||||
if card.is_pressed:
|
||||
card.stored_z_index = CardFrameworkSettings.VISUAL_PILE_Z_INDEX + i
|
||||
else:
|
||||
card.stored_z_index = i
|
||||
|
||||
|
||||
## Updates visual positions and interaction states for all cards in the pile.
|
||||
## Positions cards according to layout direction and applies interaction restrictions.
|
||||
func _update_target_positions() -> void:
|
||||
# Calculate top card position for drop zone alignment
|
||||
var last_index = _held_cards.size() - 1
|
||||
if last_index < 0:
|
||||
last_index = 0
|
||||
var last_offset = _calculate_offset(last_index)
|
||||
|
||||
# Align drop zone with top card if enabled
|
||||
if enable_drop_zone and align_drop_zone_with_top_card:
|
||||
drop_zone.change_sensor_position_with_offset(last_offset)
|
||||
|
||||
# Position each card and set interaction state
|
||||
for i in range(_held_cards.size()):
|
||||
var card = _held_cards[i]
|
||||
var offset = _calculate_offset(i)
|
||||
var target_pos = position + offset
|
||||
|
||||
# Set card appearance and position
|
||||
card.show_front = card_face_up
|
||||
card.move(target_pos, 0)
|
||||
|
||||
# Apply interaction restrictions
|
||||
if not allow_card_movement:
|
||||
card.can_be_interacted_with = false
|
||||
elif restrict_to_top_card:
|
||||
if i == _held_cards.size() - 1:
|
||||
card.can_be_interacted_with = true
|
||||
else:
|
||||
card.can_be_interacted_with = false
|
||||
|
||||
|
||||
## Calculates the visual offset for a card at the given index in the stack.
|
||||
## Respects max_stack_display limit to prevent excessive visual spreading.
|
||||
## @param index: Position of the card in the stack (0 = bottom, higher = top)
|
||||
## @returns: Vector2 offset from the pile's base position
|
||||
func _calculate_offset(index: int) -> Vector2:
|
||||
# Clamp to maximum display limit to prevent visual overflow
|
||||
var actual_index = min(index, max_stack_display - 1)
|
||||
var offset_value = actual_index * stack_display_gap
|
||||
var offset = Vector2()
|
||||
|
||||
# Apply directional offset based on pile layout
|
||||
match layout:
|
||||
PileDirection.UP:
|
||||
offset.y -= offset_value # Stack upward (negative Y)
|
||||
PileDirection.DOWN:
|
||||
offset.y += offset_value # Stack downward (positive Y)
|
||||
PileDirection.RIGHT:
|
||||
offset.x += offset_value # Stack rightward (positive X)
|
||||
PileDirection.LEFT:
|
||||
offset.x -= offset_value # Stack leftward (negative X)
|
||||
|
||||
return offset
|
||||
Reference in New Issue
Block a user