Logo

Braindead.bzh

Game Dev Hobbyist

A blog about my game dev hobby and various stuff.

Menu
Logo

Braindead.bzh

Game Dev Hobbyist

A blog about my game dev hobby and various stuff.

Drag and drop

Overview

Drag and drop is a key component of any card game. CardEngine relies on Godot own drag and drop implementation, especially the following functions of the Control node:

Most of the complexity is however hidden and and requires minimal actions from you. Containers, cards visual layer and the DropArea widget take care of all the details for you.

Container

Containers can be source for a drag and drop action. To activate this feature you have to make sure drag is enabled for your container, see here for more details. This is all you have to do, however by default the drag action will move the card itself with the mouse cursor. If you want your drag action to have a different visual, you can set a widget for that (see below).

Drag widget

Assigning a drag widget

You define which widget you want to use using the "Drag Widget" property of your container.

To do so, open the container scene file under the res://containers/<container ID>.tscn and select the root node, you will have access to the property in the Inspector. Load the widget using the property editor menu.

Creating a drag widget

A drag widget must be a control based scene. Create a new scene using the "Scene" menu of the Godot editor and choose "User Interface" as a root node. You can then build your widget using any Control or Node2D based nodes. If you want to customize your widget depending on the card being dragged, attach a new script to the root node. In the _ready() function you can connect to the drag_started() signal of the GeneralManager singleton accessible through CardEngine.general(). Then you can retrieved the dragged card using the CardEngine.general().get_dragged_card() function. Here a complete example from the demo:

extends Control

onready var _name = $Background/Name


func _ready() -> void:
    CardEngine.general().connect("drag_started", self, "_on_drag_started")


func _on_drag_started():
    var card = CardEngine.general().get_dragged_card()

    _name.text = card.data().get_text("name")

DropArea

DropArea scene: res://addons/cardengine/core/drop_area.tscn (source script)

Usage

DropArea is very simple to use, this is a Control based Node. It can be added in any scene as you would add any UI elements. You can then make your script react to a card being dropped into the area by using the dropped(card, source, on_card) signal, where:

  • card (CardInstance) is the card being drop into the area.
  • source (String) is the ID of the container from where the card is coming from.
  • on_card (CardInstance) if the DropArea contains cards (typically a container) this gives the card on which the dragged card is being dropped.

Here an example from the demo:

func _on_CardDrop_dropped(card: CardInstance, source: String, on_card: CardInstance) -> void:
    var card_mana = card.data().get_value("mana")

    if _mana >= card_mana:
        _hand.play_card(card.ref(), _discard_pile)

        if card_mana < 0:
            _mana = 0
        else:
            _mana -= card_mana

        _update_mana()

Filter

By the dragged card

You might not want all cards being dropped into your area, you can set a filter by calling the set_filter(filter) function of DropArea. The filter is of type Query, find out how to write queries at the bottom of this page.

By the source container

You can also filter the cards being dropped by the container they are coming from. To do so, add the allowed container IDs in the "Source Filter" array property of DropArea. If the array is empty the DropArea will accept cards from any source. You can also use the set_source_filter() function to set this filter in script.

By the targeted card

Coming Soontm

Special cases

Container to container

Containers can be receivers for a drag and drop action. To activate this feature you have to make sure drop is enabled for your container, see here for more details. You can retrieve the container's DropArea by using the get_drop_area() function, it is particularly useful if you need to set some filters on it (see above).

Once activated your container will emit the card_dropped(card, source, on_card) signal, connect to it to decide what to do with the card, here an example from the demo:

func _on_TokenGrid_card_dropped(card: CardInstance, source: String, on_card: CardInstance) -> void:
    if _tokens.count() >= MAX_TOKENS:
        return

    var card_mana = card.data().get_value("mana")

    if _mana >= card_mana:
        _hand.play_card(card.ref(), _discard_pile)
        _tokens.add_card(CardInstance.new(card.data()))

        if card_mana < 0:
            _mana = 0
        else:
            _mana -= card_mana

        _update_mana()

Drop placeholder

Coming Soontm

Manual re-ordering

Coming Soontm