# Card Framework API Reference Complete API reference for the Godot 4.x Card Framework addon. This framework provides a modular system for creating 2D card games with drag-and-drop functionality, flexible container management, and extensible card factories. ## Table of Contents - [Configuration](#configuration) - [CardFrameworkSettings](#cardframeworksettings) - [Core Classes](#core-classes) - [CardManager](#cardmanager) - [Card](#card) - [CardContainer](#cardcontainer) - [CardFactory](#cardfactory) - [JsonCardFactory](#jsoncardfactory) - [Specialized Containers](#specialized-containers) - [Pile](#pile) - [Hand](#hand) - [Supporting Classes](#supporting-classes) - [DraggableObject](#draggableobject) - [DropZone](#dropzone) - [HistoryElement](#historyelement) --- ## Configuration ### CardFrameworkSettings **Extends:** `RefCounted` Centralized configuration constants for all Card Framework components. This class provides consistent default values without requiring Autoload, allowing components to reference framework-wide constants directly. #### Animation Constants | Constant | Type | Value | Description | |----------|------|-------|-------------| | `ANIMATION_MOVE_SPEED` | `float` | `2000.0` | Speed of card movement animations in pixels per second | | `ANIMATION_HOVER_DURATION` | `float` | `0.10` | Duration of hover animations in seconds | | `ANIMATION_HOVER_SCALE` | `float` | `1.1` | Scale multiplier applied during hover effects | | `ANIMATION_HOVER_ROTATION` | `float` | `0.0` | Rotation in degrees applied during hover effects | #### Physics Constants | Constant | Type | Value | Description | |----------|------|-------|-------------| | `PHYSICS_HOVER_DISTANCE` | `float` | `10.0` | Distance threshold for hover detection in pixels | | `PHYSICS_CARD_HOVER_DISTANCE` | `float` | `30.0` | Distance cards move up during hover in pixels | #### Visual Layout Constants | Constant | Type | Value | Description | |----------|------|-------|-------------| | `VISUAL_DRAG_Z_OFFSET` | `int` | `1000` | Z-index offset applied to cards during drag operations | | `VISUAL_PILE_Z_INDEX` | `int` | `3000` | Z-index for pile cards to ensure proper layering | | `VISUAL_SENSOR_Z_INDEX` | `int` | `-1000` | Z-index for drop zone sensors (below everything) | | `VISUAL_OUTLINE_Z_INDEX` | `int` | `1200` | Z-index for debug outlines (above UI) | #### Container Layout Constants | Constant | Type | Value | Description | |----------|------|-------|-------------| | `LAYOUT_DEFAULT_CARD_SIZE` | `Vector2` | `Vector2(150, 210)` | Default card size used throughout the framework | | `LAYOUT_STACK_GAP` | `int` | `8` | Distance between stacked cards in piles | | `LAYOUT_MAX_STACK_DISPLAY` | `int` | `6` | Maximum cards to display in stack before hiding | | `LAYOUT_MAX_HAND_SIZE` | `int` | `10` | Maximum number of cards in hand containers | | `LAYOUT_MAX_HAND_SPREAD` | `int` | `700` | Maximum pixel spread for hand arrangements | #### Debug Constants | Constant | Type | Value | Description | |----------|------|-------|-------------| | `DEBUG_OUTLINE_COLOR` | `Color` | `Color(1, 0, 0, 1)` | Color used for sensor outlines and debug indicators | #### Usage ```gdscript # Reference constants directly in component @export variables @export var moving_speed: int = CardFrameworkSettings.ANIMATION_MOVE_SPEED @export var hover_distance: int = CardFrameworkSettings.PHYSICS_HOVER_DISTANCE # Or use in code z_index = stored_z_index + CardFrameworkSettings.VISUAL_DRAG_Z_OFFSET ``` --- ## Core Classes ### CardManager **Extends:** `Control` The central orchestrator for all card game operations. Manages card containers, handles drag-and-drop operations, and maintains game history for undo functionality. #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `card_size` | `Vector2` | `Vector2(150, 210)` | Default size for all cards in the game | | `card_factory_scene` | `PackedScene` | - | Scene containing the CardFactory implementation | | `debug_mode` | `bool` | `false` | Enables visual debugging for drop zones | #### Methods ##### undo() -> void Undoes the last card movement operation by restoring cards to their previous container. ```gdscript card_manager.undo() ``` ##### reset_history() -> void Clears all stored history elements, preventing further undo operations. ```gdscript card_manager.reset_history() ``` #### Internal Methods These methods are called automatically by the framework: - `_add_card_container(id: int, card_container: CardContainer)` - Registers a container - `_delete_card_container(id: int)` - Unregisters a container - `_on_drag_dropped(cards: Array)` - Handles completed drag operations - `_add_history(to: CardContainer, cards: Array)` - Records movement for undo --- ### Card **Extends:** `DraggableObject` Represents an individual playing card with front/back faces and interaction capabilities. #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `card_name` | `String` | `""` | Unique identifier for the card | | `card_size` | `Vector2` | `Vector2(150, 210)` | Dimensions of the card | | `front_image` | `Texture2D` | - | Texture for card front face | | `back_image` | `Texture2D` | - | Texture for card back face | | `show_front` | `bool` | `true` | Whether front face is visible | #### Variables | Variable | Type | Description | |----------|------|-------------| | `card_info` | `Dictionary` | Additional card data from JSON | | `card_container` | `CardContainer` | Container currently holding this card | #### Methods ##### set_faces(front_face: Texture2D, back_face: Texture2D) -> void Sets both front and back textures for the card. ```gdscript card.set_faces(front_texture, back_texture) ``` ##### return_card() -> void Returns card to its original position with no rotation. ```gdscript card.return_card() ``` ##### start_hovering() -> void Initiates hover effect, raising card visually and adjusting global hover count. ```gdscript card.start_hovering() ``` ##### end_hovering(restore_object_position: bool) -> void Ends hover effect and optionally restores position. ```gdscript card.end_hovering(true) # Restore position card.end_hovering(false) # Keep current position ``` ##### set_holding() -> void *[Deprecated]* Legacy method for setting holding state. Use state machine transitions instead. ```gdscript card.set_holding() # Put card into holding state ``` ##### get_string() -> String Returns string representation of the card for debugging. ```gdscript var card_info = card.get_string() # Returns card_name ``` #### Static Variables | Variable | Type | Description | |----------|------|-------------| | `hovering_card_count` | `int` | Global count of currently hovering cards | --- ### CardContainer **Extends:** `Control` Abstract base class for all card containers. Provides core functionality for holding, managing, and organizing cards with drag-and-drop support. #### Drop Zone Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `enable_drop_zone` | `bool` | `true` | Enables drop zone functionality | | `sensor_size` | `Vector2` | `Vector2(0, 0)` | Size of drop sensor (follows card_size if unset) | | `sensor_position` | `Vector2` | `Vector2(0, 0)` | Position offset for drop sensor | | `sensor_texture` | `Texture` | - | Visual texture for sensor (debugging) | | `sensor_visibility` | `bool` | `false` | Whether sensor is visible | #### Variables | Variable | Type | Description | |----------|------|-------------| | `unique_id` | `int` | Auto-generated unique identifier | | `cards_node` | `Control` | Node containing all card children | | `card_manager` | `CardManager` | Reference to parent CardManager | | `debug_mode` | `bool` | Debug mode state from CardManager | #### Core Methods ##### add_card(card: Card, index: int = -1) -> void Adds a card to the container at specified index (-1 for end). ```gdscript container.add_card(my_card) # Add to end container.add_card(my_card, 0) # Add to beginning ``` ##### remove_card(card: Card) -> bool Removes a card from the container. Returns true if successful. ```gdscript var success = container.remove_card(my_card) ``` ##### has_card(card: Card) -> bool Checks if container holds the specified card. ```gdscript if container.has_card(my_card): print("Card is in this container") ``` ##### get_card_count() -> int Returns the number of cards currently in the container. ```gdscript var count = container.get_card_count() print("Container has %d cards" % count) ``` ##### clear_cards() -> void Removes all cards from the container. ```gdscript container.clear_cards() ``` ##### move_cards(cards: Array, index: int = -1, with_history: bool = true) -> bool Moves multiple cards to this container with optional history tracking. ```gdscript var cards_to_move = [card1, card2, card3] container.move_cards(cards_to_move, 0, true) # Move to beginning with history ``` ##### shuffle() -> void Randomly shuffles all cards in the container using Fisher-Yates algorithm. ```gdscript deck_container.shuffle() ``` ##### undo(cards: Array, from_indices: Array = []) -> void Restores cards to their original positions with index precision. Supports both simple restoration and precise index-based positioning for complex undo scenarios. **Parameters:** - `cards`: Array of cards to restore to this container - `from_indices`: Optional array of original indices for precise positioning (since v1.1.4) **Features:** - **Adaptive Algorithm**: Automatically detects consecutive vs non-consecutive card groups - **Order Preservation**: Maintains correct card order for bulk consecutive moves - **Fallback Safety**: Gracefully handles missing or invalid index data ```gdscript # Simple undo (backward compatible) source_container.undo([card1, card2]) # Precise index-based undo (new in v1.1.4) source_container.undo([card1, card2, card3], [0, 1, 2]) # Handles complex scenarios automatically hand_container.undo(moved_cards, original_indices) ``` #### Drop Zone Methods ##### check_card_can_be_dropped(cards: Array) -> bool Determines if the provided cards can be dropped into this container. ```gdscript if container.check_card_can_be_dropped([my_card]): # Cards can be dropped here ``` ##### get_partition_index() -> int Gets the drop partition index based on mouse position. Returns -1 if no partitioning. ```gdscript var drop_index = container.get_partition_index() ``` #### Event Handlers ##### on_card_move_done(_card: Card) -> void Called when a card finishes moving. Override in subclasses for custom behavior. ```gdscript func on_card_move_done(card: Card): print("Card movement completed: ", card.card_name) ``` ##### on_card_pressed(_card: Card) -> void Called when a card in this container is pressed. Override for custom behavior. ```gdscript func on_card_pressed(card: Card): print("Card pressed: ", card.card_name) ``` #### Utility Methods ##### hold_card(card: Card) -> void Puts a card into holding state, preparing it for drag operations. ```gdscript container.hold_card(my_card) # Put card into holding state ``` ##### get_string() -> String Returns string representation for debugging. ```gdscript print(container.get_string()) # "card_container: 1" ``` #### Abstract Methods These methods should be overridden in subclasses: ##### update_card_ui() -> void Updates visual positioning and appearance of all cards. ##### _card_can_be_added(_cards: Array) -> bool Returns true if the specified cards can be added to this container. Base implementation always returns true. ##### _update_target_positions() -> void Calculates and applies target positions for all cards. ##### _update_target_z_index() -> void Updates Z-index layering for all cards. --- ### CardFactory **Extends:** `Node` Abstract base class for creating cards. Implement this class to define custom card creation logic. #### Variables | Variable | Type | Description | |----------|------|-------------| | `preloaded_cards` | `Dictionary` | Cache for card data to improve performance | | `card_size` | `Vector2` | Size to apply to created cards | #### Abstract Methods ##### create_card(card_name: String, target: CardContainer) -> Card Creates and returns a new card instance. Must be implemented by subclasses. ```gdscript # In your custom factory: func create_card(card_name: String, target: CardContainer) -> Card: var new_card = card_scene.instantiate() # Configure card... return new_card ``` ##### preload_card_data() -> void Preloads card data for improved performance. Called automatically by CardManager. ```gdscript func preload_card_data() -> void: # Load and cache card data pass ``` --- ### JsonCardFactory **Extends:** `CardFactory` Concrete implementation of CardFactory that creates cards from JSON metadata and image assets. #### Properties | Property | Type | Description | |----------|------|-------------| | `default_card_scene` | `PackedScene` | Base card scene to instantiate | | `card_asset_dir` | `String` | Directory containing card image files | | `card_info_dir` | `String` | Directory containing JSON card definitions | | `back_image` | `Texture2D` | Common back face texture for all cards | #### Methods ##### create_card(card_name: String, target: CardContainer) -> Card Creates a card from JSON data and image assets. ```gdscript var my_card = factory.create_card("ace_of_spades", target_container) ``` The factory looks for: - JSON file: `{card_info_dir}/{card_name}.json` - Image file: `{card_asset_dir}/{front_image}` (from JSON) #### JSON Card Format Cards are defined using JSON files with the following structure: ```json { "name": "ace_of_spades", "front_image": "cardSpadesA.png", "suit": "spades", "value": "A", "custom_property": "additional_data" } ``` **Required fields:** - `front_image`: Filename of the card's front face image **Optional fields:** - `name`: Display name for the card - Any additional properties for game-specific logic --- ## Specialized Containers ### Pile **Extends:** `CardContainer` A container that stacks cards in a pile formation with configurable direction and display options. #### Enums ```gdscript enum PileDirection { UP, # Cards stack upward DOWN, # Cards stack downward LEFT, # Cards stack leftward RIGHT # Cards stack rightward } ``` #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `stack_display_gap` | `int` | `8` | Pixel distance between cards in stack | | `max_stack_display` | `int` | `6` | Maximum cards to show stacked | | `card_face_up` | `bool` | `true` | Whether cards show front face | | `layout` | `PileDirection` | `UP` | Direction to stack cards | | `allow_card_movement` | `bool` | `true` | Whether cards can be moved | | `restrict_to_top_card` | `bool` | `true` | Only top card is interactive | | `align_drop_zone_with_top_card` | `bool` | `true` | Drop zone follows top card | #### Methods ##### get_top_cards(n: int) -> Array Returns the top N cards from the pile. ```gdscript var top_three = pile.get_top_cards(3) # Get top 3 cards var top_card = pile.get_top_cards(1)[0] # Get just the top card ``` #### Usage Example ```gdscript # Create a deck pile @export var deck_pile: Pile func _ready(): deck_pile.layout = Pile.PileDirection.UP deck_pile.card_face_up = false # Cards face down deck_pile.restrict_to_top_card = true # Add cards to deck for card_name in card_names: var card = card_factory.create_card(card_name, deck_pile) ``` --- ### Hand **Extends:** `CardContainer` A container that displays cards in a fan-like hand formation with curves and spacing. #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `max_hand_size` | `int` | `10` | Maximum cards that can be held | | `max_hand_spread` | `int` | `700` | Maximum pixel spread of hand | | `card_face_up` | `bool` | `true` | Whether cards show front face | | `card_hover_distance` | `int` | `30` | Distance cards hover when interacted with | #### Curve Properties | Property | Type | Description | |----------|------|-------------| | `hand_rotation_curve` | `Curve` | Controls rotation of cards across hand | | `hand_vertical_curve` | `Curve` | Controls vertical positioning of cards | #### Drop Zone Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `align_drop_zone_size_with_current_hand_size` | `bool` | `true` | Drop zone adapts to hand size | | `swap_only_on_reorder` | `bool` | `false` | Reordering swaps positions instead of shifting | #### Methods ##### get_random_cards(n: int) -> Array Returns N random cards from the hand without removing them. ```gdscript var random_cards = hand.get_random_cards(3) ``` ##### move_cards(cards: Array, index: int = -1, with_history: bool = true) -> bool Enhanced version of CardContainer.move_cards() with hand-specific optimizations: - **Single Card Reordering**: Optimized reordering when moving cards within same hand - **Swap Mode**: Uses swap_card() when `swap_only_on_reorder` is enabled - **Fallback**: Uses parent implementation for external card moves ```gdscript # Move card to specific position in hand hand.move_cards([my_card], 2) # Move to index 2 # External card move (uses parent implementation) hand.move_cards([external_card], -1) # Add external card to end ``` ##### swap_card(card: Card, index: int) -> void Swaps a card with the card at the specified index. ```gdscript hand.swap_card(my_card, 0) # Move card to first position ``` #### Usage Example ```gdscript # Configure hand curves @export var hand: Hand func _ready(): # Create rotation curve: -30° to +30° hand.hand_rotation_curve = Curve.new() hand.hand_rotation_curve.add_point(0.0, -30.0) hand.hand_rotation_curve.add_point(1.0, 30.0) # Create vertical curve: arc shape hand.hand_vertical_curve = Curve.new() hand.hand_vertical_curve.add_point(0.0, 0.0) hand.hand_vertical_curve.add_point(0.5, 50.0) # Peak in middle hand.hand_vertical_curve.add_point(1.0, 0.0) ``` --- ## Supporting Classes ### DraggableObject **Extends:** `Control` State machine-based drag-and-drop system with Tween animations. Provides robust interaction handling with safe state transitions and smooth visual feedback. #### Enums ##### DraggableState Defines possible interaction states with controlled transitions. | State | Description | |-------|-------------| | `IDLE` | Default state - ready for interaction | | `HOVERING` | Mouse over with visual feedback | | `HOLDING` | Active drag state following mouse | | `MOVING` | Programmatic movement ignoring input | #### Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `moving_speed` | `int` | `2000` | Speed of programmatic movement (pixels/second) | | `can_be_interacted_with` | `bool` | `true` | Whether object responds to input | | `hover_distance` | `int` | `10` | Distance to hover when interacted with | | `hover_scale` | `float` | `1.1` | Scale multiplier when hovering | | `hover_rotation` | `float` | `0.0` | Rotation in degrees when hovering | | `hover_duration` | `float` | `0.10` | Duration for hover animations | #### State Management | Variable | Type | Description | |----------|------|-------------| | `current_state` | `DraggableState` | Current interaction state | | `is_pressed` | `bool` | Legacy compatibility - mouse pressed | | `is_holding` | `bool` | Legacy compatibility - being dragged | | `stored_z_index` | `int` | Original Z-index before interactions | #### Methods ##### move(target_destination: Vector2, degree: float) -> void Moves object to target position with optional rotation using smooth Tween animation. Automatically transitions to MOVING state. ```gdscript draggable.move(new_position, deg_to_rad(45)) # Move with 45° rotation draggable.move(Vector2(100, 200), 0) # Move without rotation ``` ##### return_to_original() -> void Returns the object to its original position with smooth animation. Sets internal tracking flag for proper position management. ```gdscript draggable.return_to_original() # Return to original position and rotation ``` ##### change_state(new_state: DraggableState) -> bool Safely transitions between interaction states using predefined rules. Returns true if transition was successful. ```gdscript # Manual state transitions if draggable.change_state(DraggableObject.DraggableState.HOVERING): print("Now hovering") # State machine prevents invalid transitions draggable.change_state(DraggableObject.DraggableState.MOVING) # Force to MOVING ``` **State Transition Rules:** - `IDLE` → `HOVERING`, `HOLDING`, `MOVING` - `HOVERING` → `IDLE`, `HOLDING`, `MOVING` - `HOLDING` → `IDLE`, `MOVING` - `MOVING` → `IDLE` #### Virtual Methods ##### _on_move_done() -> void Called when movement animation completes. Override in subclasses for custom behavior. ```gdscript func _on_move_done(): print("Movement finished") # Custom post-movement logic ``` ##### _can_start_hovering() -> bool Virtual method to determine if hovering animation can start. Override for custom conditions. ```gdscript func _can_start_hovering() -> bool: return not is_card_locked # Example: prevent hover if locked ``` #### Animation System The new Tween-based animation system provides: - **Smooth Transitions**: All state changes use smooth animations - **Memory Management**: Proper cleanup of animation resources - **Interrupt Handling**: Safe animation interruption and cleanup - **Performance**: Optimized for multiple simultaneous animations --- ### DropZone **Extends:** `Control` Handles drop detection and partitioning for card containers. #### Properties | Property | Type | Description | |----------|------|-------------| | `sensor_size` | `Vector2` | Size of the drop detection area | | `sensor_position` | `Vector2` | Position offset of the sensor | | `sensor_texture` | `Texture` | Visual texture for debugging | | `sensor_visible` | `bool` | Whether sensor is visible | | `sensor_outline_visible` | `bool` | Whether debug outline is visible | | `accept_types` | `Array` | Array of acceptable drop types | #### Variables | Variable | Type | Description | |----------|------|-------------| | `vertical_partition` | `Array` | Global X coordinates for vertical partitions | | `horizontal_partition` | `Array` | Global Y coordinates for horizontal partitions | #### Methods ##### init(_parent: Node, accept_types: Array = []) -> void Initializes the drop zone with parent reference and accepted types. ```gdscript drop_zone.init(self, ["card"]) ``` ##### check_mouse_is_in_drop_zone() -> bool Returns true if mouse cursor is within the drop zone area. ```gdscript if drop_zone.check_mouse_is_in_drop_zone(): # Mouse is over drop zone ``` ##### set_sensor(_size: Vector2, _position: Vector2, _texture: Texture, _visible: bool) -> void Configures the drop sensor properties. ```gdscript drop_zone.set_sensor(Vector2(200, 300), Vector2(10, 10), null, false) ``` ##### set_vertical_partitions(positions: Array) -> void Sets vertical partition lines for precise drop positioning. ```gdscript drop_zone.set_vertical_partitions([100, 200, 300]) # Three partition lines ``` ##### set_horizontal_partitions(positions: Array) -> void Sets horizontal partition lines for precise drop positioning. ```gdscript drop_zone.set_horizontal_partitions([50, 150, 250]) # Three partition lines ``` ##### get_vertical_layers() -> int Returns the vertical partition index under the mouse cursor. ```gdscript var partition = drop_zone.get_vertical_layers() if partition != -1: print("Dropping in partition: ", partition) ``` ##### get_horizontal_layers() -> int Returns the horizontal partition index under the mouse cursor. --- ### HistoryElement **Extends:** `Object` Represents a single card movement operation for undo functionality. #### Variables | Variable | Type | Description | |----------|------|-------------| | `from` | `CardContainer` | Source container | | `to` | `CardContainer` | Destination container | | `cards` | `Array` | Array of cards that were moved | #### Methods ##### get_string() -> String Returns string representation for debugging. ```gdscript var history_info = history_element.get_string() # Returns: "from: [container_1], to: [container_2], cards: [ace_of_spades, king_of_hearts]" ``` --- ## Usage Patterns ### Basic Setup ```gdscript # Scene structure: # CardManager (CardManager) # ├── DeckPile (Pile) # ├── PlayerHand (Hand) # └── DiscardPile (Pile) @onready var card_manager: CardManager = $CardManager @onready var deck: Pile = $CardManager/DeckPile @onready var hand: Hand = $CardManager/PlayerHand func _ready(): # Cards are automatically managed by CardManager deal_initial_cards() func deal_initial_cards(): var cards_to_deal = deck.get_top_cards(7) hand.move_cards(cards_to_deal) ``` ### Custom Container ```gdscript class_name CustomPile extends CardContainer @export var max_cards: int = 5 func _card_can_be_added(cards: Array) -> bool: return _held_cards.size() + cards.size() <= max_cards func _update_target_positions(): for i in range(_held_cards.size()): var card = _held_cards[i] var offset = Vector2(i * 20, i * 5) # Slight offset for each card card.move(global_position + offset, 0) ``` ### Custom Card Factory ```gdscript class_name MyCardFactory extends CardFactory @export var custom_card_scene: PackedScene func create_card(card_name: String, target: CardContainer) -> Card: var card = custom_card_scene.instantiate() card.card_name = card_name # Custom card setup logic return card func preload_card_data(): # Custom preloading logic pass ``` This API reference provides complete documentation for all public methods and properties in the Card Framework. For implementation examples, see the included example projects and the FreeCell game demonstration.