You're going to build a tiny working thing: a scene with a single Card, clicked to flip, with a signal emitted. When you finish, you'll have written your first CardData resource, your first custom scene, your first script, and you'll have wired up a signal. Everything after this is more of the same.
lexicon-duel (from Lesson 1)1Create a CardData resource class.
In the FileSystem dock, right-click โ New โ Folder โ scripts. Inside it, right-click โ New โ Script. Name it card_data.gd. Paste:
class_name CardData
extends Resource
@export var letter: String = "A"
@export var value: int = 1
func describe() -> String:
return "%s (%d)" % [letter, value]
Save. Godot will re-parse and the CardData type will be globally available.
2Create a card resource instance.
Right-click the FileSystem root โ New โ Folder โ cards. In that folder, right-click โ New โ Resource. Type CardData in the dialog. Save as a_tile.tres. It opens in the Inspector. Set letter: A, value: 1. Save.
3Create the Card scene.
Scene menu โ New Scene. "Other Node" โ Node2D. Rename the root to Card. Save as scenes/card.tscn (create the folder if needed).
Add children โ right-click the root โ Add Child Node:
ColorRect, name it Background. In the Inspector set Size to (120, 160) and Color to a dark gray.Label, name it LetterLabel. Position it at (20, 20), set Text to "A" in the Inspector. Set Font Size (Theme Overrides โ Font Sizes) to 64.Area2D, name it TouchArea. Add a child CollisionShape2D. In the Inspector, create a new RectangleShape2D for its Shape and size it to roughly (120, 160), positioned at the center of the card.4Attach a script to Card.
Click the Card root, then the scroll-with-plus icon ("Attach Script"). Accept the defaults. Paste:
extends Node2D
class_name Card
signal card_flipped(card: Card)
@export var data: CardData
@onready var label: Label = $LetterLabel
@onready var touch: Area2D = $TouchArea
var is_flipped := false
func _ready() -> void:
if data:
label.text = data.letter
touch.input_event.connect(_on_touch_input)
func _on_touch_input(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
if event is InputEventMouseButton and event.pressed:
flip()
func flip() -> void:
is_flipped = !is_flipped
label.text = "โฆ" if is_flipped else data.letter
card_flipped.emit(self)
print("card %s flipped -> %s" % [data.letter, is_flipped])
5Assign the data resource.
With the Card node selected in the scene, look at the Inspector. There's a Data slot (because @export var data: CardData). Drag cards/a_tile.tres from the FileSystem dock into that slot.
6Create a main scene that hosts the Card.
Scene โ New Scene โ Node2D. Rename to Main. Save as scenes/main.tscn. Drag scenes/card.tscn from the FileSystem dock into the Scene dock, dropping it onto Main. Position the card somewhere visible (e.g. (200, 200)).
Project โ Project Settings โ Application โ Run โ set Main Scene to main.tscn.
7Run it.
Press F5. A window opens. You see an "A" on a gray rectangle. Click it. The letter changes to โฆ. The output log prints card A flipped -> true. Click again. Flips back.
That's the complete loop: scene composition, script behavior, signal emission, data-driven resource.
If you finish with time to spare:
data slot and re-run to see the label change.Tween to the flip: on flip, rotate the card 180ยฐ over 0.2s. Hint: create_tween().tween_property(self, "rotation", PI, 0.2).card_flipped from Main's script and print a "card flipped at position X" message.class_name CardData line has to be at module scope, before imports. Also save the file โ Godot parses on save.data.letter: you forgot to drag a_tile.tres into the Inspector slot._ready ran (add a print("ready") at the top).When it runs, return to the dashboard and check off this exercise.