This system implements card and deck mechanics in Godot Engine. It features drawing, shuffling, and many more standard card behaviors and interactions. A standard deck of playing cards comes packaged with this plugin, but it can really be used for any kind of card based game.
var cards = [
preload("res://path/to/your/card1.tres"),
preload("res://path/to/your/card2.tres"),
preload("res://path/to/your/card3.tres")
]
@onready var draw_pile: Deck = $DrawPile
@onready var hand: Deck = $Hand
func _ready():
for data in cards:
draw_pile.create_from_card_data(data)
draw_pile.shuffle()
draw_pile.move_card_to_deck(hand, draw_pile.get_top_card())
- Download the latest release
- Unpack the
addons/deckbuilder-framworkinto your/addonsfolder within the Godot project
- Extend the
CardDataresource script with any data your cards will need - Create a
Cardscene that implements yourCardData - Add a
Deckinto your game - Create cards in the deck using the
create_from_card_datamethod - Connect the signals decks emit and use them make your game
Resource data. Generally this data will initialize your Card scene. After you setup your CardData you can create your card resources (.tres files) that use this as their script.
# playing_card.gd
class_name PlayingCardData extends CardData
enum SUITS {
SPADES,
CLUBS,
DIAMONDS,
HEARTS
}
@export var suit : SUITS
@export var value : int
@export var texture : Resource
After setting this up you create your card resources as needed (spades-a.tres, spades-2.tres, spades-3.tres, etc.).
The only requirement here is that you also provide it a card_scene PackedScene which will be explained next.
A root node scene. Create your in-game card scene by using this as the root node. Generally this changes its display using it's card_data in the update_display method.
set_card_data(card_data : CardData) -> void
Set this scenes card data and updates the display.
set_auto_position_enabled(val : bool) -> void
Turns on/off autopositioning. This is helpful if you want the card in a deck but you also want to manually position the card somewhere else in the game world.
update_display() -> void
Manually update the card display. This is automatically called on _ready but you may also want to call it manually when one of the Cards's card_data properties change.
# playing_card.tscn
class_name PlayingCard extends Card
@onready var texture_rect: TextureRect = $TextureRect
func update_display():
texture_rect.texture = card_data.texture
A control node that manages a stack of cards. This is the main node your game will interact with and listen for signals on.
At first listening for signals on the deck instead of on the card may seem unintuitive but this allows you to easily manage different interactions on cards on different decks. For example, your game shouldn't necessarily listen for a mouse entered signal on an individual card scene, it should listen for the deck signaling that a card within it has had the mouse enter it.
mouse_entered_card(card : Card)- fires when the mouse enters the cardmouse_exited_card(card : Card)- fires when the mouse exits the cardtop_card_clicked(card : Card)- fires when the top card of a deck is clickedcard_clicked(card : Card)- fires when any card in the deck is clickedcard_picked_up(card : Card)- fires when there is a mouse down event on a draggable cardstart_card_drag(card : Card)- fires when a card starts being draggedcard_dropped(card : Card, dropped_on_deck : Deck)- fires when there is a mouse up event on a draggable cardcards_updated- fires when cards enter or leave the deck
There is a quirk with the mouse_exited_card signal. It doesn't fire until the mouse takes an action. So for example, it doesn't necessarily fire immediately after card_dropped. The user must make a mouse action after dropping to trigger this exit event.
x_spread: float – Horizontal spread of cards in the decky_spread: float – Vertical spread of cards in the deckmax_stack_size: int – Maximum number of cards displayed in a stackeddrag_behavior: DRAG_BEHAVIOR – Dragging policy (NONE, ALL, TOP, CUSTOM).stack_behavior: STACK_BEHAVIOR – Stacking policy (EXACT, CENTERED).card_drag_over_card_behavior: CARD_DRAG_OVER_CARD_BEHAVIOR – Stacking policy (NONE, SWAP_POSITIONS).hand_rotation_curve: Curve – Rotation curve for hands. This works best as a 2-point linear rise from -X to +Xhand_vertical_curve: Curve – Vertical curve for hands. This works best as a 3-point ease in/out from 0 to X to 0
create_from_card_data(card_data: CardData) -> Card
Creates a new card instance based on the provided CardData and adds it to the deck.
var card_data = load("res://path/to/card_data.tres")
var new_card = deck.create_from_card_data(card_data)
move_card_to_deck(deck: Deck, card: Card)
Moves a card from one deck to another
deck1.move_card_to_deck(deck2, card)
shuffle() -> void
Randomizes the order of cards in the deck.
deck.shuffle()
get_top_card() -> Card
Retrieves the top card of the deck without removing it.
var top_card = deck.get_top_card()
if top_card:
print("Top card is:", top_card, top_card.card_data)
custom_can_card_be_dragged(card: Card) -> bool
Determines whether a specified card can be dragged. This method is intended to be overridden for custom dragging behavior when drag_behavior is set to DRAG_BEHAVIOR.CUSTOM
func custom_can_card_be_dragged(card: Card) -> bool:
return card.card_data.some_value >= 3
is_holding_a_card() -> bool
Determines whether the deck is currently holding a card
if deck.is_holding_a_card():
print(deck.get_held_card())
get_held_card() -> Card
Returns the held card if there is one
print(deck.get_held_card())
Thanks and have fun!