Lesson 09
The payoff loop. When a piece locks, we clear any full rows using the Board logic from Lesson 4, award points that reward multi-line clears, and redraw the settled board.
We already wrote board.clear_full_rows(). Now call it during locking and score the result. Update _lock_piece() in main.gd:
var score: int = 0
var lines_cleared_total: int = 0
func _lock_piece() -> void:
for cell in active_piece.get_cells():
board.set_cell(cell.x, cell.y, active_piece.color_id)
active_piece.queue_free()
active_piece = null
var cleared: int = board.clear_full_rows()
if cleared > 0:
_award_score(cleared)
_render_board()
spawn_piece()Clearing four rows at once should be worth far more than four singles. A simple, satisfying table:
# Points for clearing N rows with a single piece.
const LINE_SCORES: Array[int] = [0, 100, 300, 500, 800]
func _award_score(cleared: int) -> void:
cleared = clampi(cleared, 0, 4)
score += LINE_SCORES[cleared]
lines_cleared_total += cleared
print("Cleared %d | score %d | lines %d" % [cleared, score, lines_cleared_total])Why non-linear
1→100, 2→300, 3→500, 4→800. The jump from 4×100 (=400) to 800 for a "tetris" gives skilled players a reason to build up and clear four at once. clampi keeps the index safe even if logic ever reports 5+.
Redraw after clearing
_render_board() runs after clear_full_rows(), so the screen always reflects post-collapse data. If you ever redraw before clearing, cleared rows briefly linger. Order matters.
Checkpoint — expected state