Lesson 05
A piece is a small set of cells with a shape and a color. This lesson defines the seven classic shapes as data, builds a Piece that draws itself from live Cell scenes, and spawns one at the top of the well.
Each shape is a list of (col, row) offsets from the piece's origin. This is all a shape is — no images required.
# Seven shapes, each a list of Vector2i offsets from the piece origin,
# plus a color id (1..7). We keep these in one place: shapes.gd.
extends RefCounted
class_name Shapes
# Color id -> actual Color, used when drawing.
const COLORS: Array[Color] = [
Color.BLACK, # 0 unused (empty)
Color("#4a8fe7"), # 1 I - blue
Color("#e8b24a"), # 2 O - amber
Color("#a988e0"), # 3 T - violet
Color("#5cc98b"), # 4 S - green
Color("#e56b6f"), # 5 Z - red
Color("#e0863f"), # 6 L - orange
Color("#6bd4c4"), # 7 J - teal
]
# Each entry: { "id": int, "cells": Array[Vector2i] }
const SHAPES: Array = [
{ "id": 1, "cells": [Vector2i(-1,0), Vector2i(0,0), Vector2i(1,0), Vector2i(2,0)] }, # I
{ "id": 2, "cells": [Vector2i(0,0), Vector2i(1,0), Vector2i(0,1), Vector2i(1,1)] }, # O
{ "id": 3, "cells": [Vector2i(-1,0), Vector2i(0,0), Vector2i(1,0), Vector2i(0,1)] }, # T
{ "id": 4, "cells": [Vector2i(0,0), Vector2i(1,0), Vector2i(-1,1),Vector2i(0,1)] }, # S
{ "id": 5, "cells": [Vector2i(-1,0), Vector2i(0,0), Vector2i(0,1), Vector2i(1,1)] }, # Z
{ "id": 6, "cells": [Vector2i(-1,0), Vector2i(0,0), Vector2i(1,0), Vector2i(1,1)] }, # L
{ "id": 7, "cells": [Vector2i(-1,0), Vector2i(0,0), Vector2i(1,0), Vector2i(-1,1)] },# J
]
static func random_shape() -> Dictionary:
return SHAPES[randi() % SHAPES.size()]static func
static func belongs to the class, not an instance — call it as Shapes.random_shape() without creating a Shapes object. randi() % n gives a random int in 0..n-1.
Piece.piece.tscn.piece.gd to it (code below).The Piece holds its grid origin, its list of cell offsets, and the live Cell nodes it spawns to draw itself.
extends Node2D
class_name Piece
const CELL_SIZE: int = 32
const CellScene: PackedScene = preload("res://cell.tscn")
var color_id: int = 1
var offsets: Array = [] # Array[Vector2i], relative to origin
var origin: Vector2i = Vector2i.ZERO # grid position of the piece
var _cell_nodes: Array = [] # the visual Cell instances
# Configure from a Shapes dictionary and a starting origin.
func setup(shape: Dictionary, start_origin: Vector2i) -> void:
color_id = shape["id"]
offsets = shape["cells"].duplicate()
origin = start_origin
_build_visuals()
_redraw()
# Absolute grid cells this piece currently occupies.
func get_cells() -> Array:
var result: Array = []
for off in offsets:
result.append(origin + off)
return result
# Spawn one Cell node per offset (once).
func _build_visuals() -> void:
for off in offsets:
var c: Cell = CellScene.instantiate()
add_child(c)
c.set_color(Shapes.COLORS[color_id])
_cell_nodes.append(c)
# Move the visual cells to match origin + offsets.
func _redraw() -> void:
for i in range(offsets.size()):
var grid_pos: Vector2i = origin + offsets[i]
_cell_nodes[i].set_grid_position(grid_pos)Visuals built once, moved often
We instantiate the Cell nodes a single time in _build_visuals(), then just reposition them in _redraw(). Re-instantiating every frame would leak nodes and tank performance. Build once, move many.
Replace any leftover temporary code in main.gd. Add a spawn method and call it once at start:
# add near the top of main.gd, with the other consts/vars:
const PieceScene: PackedScene = preload("res://piece.tscn")
var active_piece: Piece = null
# The column where new pieces appear (middle-ish).
const SPAWN_ORIGIN: Vector2i = Vector2i(4, 1)
func spawn_piece() -> void:
active_piece = PieceScene.instantiate()
add_child(active_piece)
active_piece.setup(Shapes.random_shape(), SPAWN_ORIGIN)Then call spawn_piece() at the end of _ready():
func _ready() -> void:
_draw_border()
spawn_piece()Nothing falls yet
The piece just sits there — we haven't added the fall timer or movement. That's Lessons 6 and 7. Right now we're only confirming that shapes spawn and draw correctly.
Checkpoint — expected state
shapes.gd data file with 7 shapes and a color table.piece.tscn that draws itself from offset data.