Game Design & Development · Tiny-Loop Tutorial · Archetype #4
Tutorial: Maze Game
This is the exact Maze Game archetype from What Makes a Game? — already built and running below. Play it, then swap the pre-built sprites, wall theme, and maze layout using the panel underneath. You can't break the loop itself; that part is locked. Once you've tuned a version you like, you'll build this same architecture two more times: with Scratch's blocks, then from real scratch in JavaScript.
🗺️ The Architecture
Every tiny-loop game starts as a concept, then gets broken into a core loop, a systems list, and a structure — before anyone touches sprites or colors. Here's the Maze Game's architecture:
The four systems, in order of execution on every key press:
- Input system — reads the arrow key pressed and computes the one target tile in that direction.
- Wall collision system — checks whether the target tile is a wall; if it is, the move is cancelled and the player stays put.
- Step counter system — only counts a step when a move actually succeeds (feedback for the player).
- Goal detection system — checks the player's tile against the goal tile every move; matching tiles ends the game.
🎮 Play & Customize
Move one tile at a time with Arrow keys, W A S D, or the touch D-pad below the game. Walls block you completely — find the path to the goal.
💡 Click inside the game first — that gives it keyboard focus so the arrow keys move the player instead of scrolling the page.
Tune the Game (limited, on purpose)
Notice what you can't change here: there's no field for "how wall collision works" or "how the goal is detected." That's the engine — the part every version of this game shares. You're only tuning content, not rewriting architecture. That's the limit, on purpose.
What Move Animation Speed actually touches in the engine: it only picks a duration from a lookup table (180ms / 110ms / 60ms) that the tile-slide animation plays over — the tile-by-tile logic in tryMove() that checks walls and the goal runs exactly the same either way. The Maze Layout and Wall Theme selects swap which grid string and color pair the locked renderer reads; the renderer never looks at what the strings mean, only where the # characters are.
👀 Peek at the Code
The game running above is this code — nothing hidden. It's split into two parts on purpose: a small config object you just edited with the panel, and a locked engine that reads it.
✏️ Config — this is what the panel above editsconst config = { player: '🤖', goal: '🔑', wall: 'lab', layout: 'zigzag', moveSpeed: 2 };
👆 This block updates live — hit "Apply & Restart" above and watch the exact values change here. There's no separate "demo" version of the code; this is it.
🔒 Engine — locked, shared by every version of this gamefunction tryMove(dx, dy) { const tx = player.col + dx, ty = player.row + dy; // 1. wall collision: cancel the move if the target tile is a wall if (maze[ty][tx] === '#') return; // 2. move succeeds: update position player.col = tx; player.row = ty; // 3. only count steps that actually happen steps++; updateHUD(); // 4. check the goal every successful move if (tx === goal.col && ty === goal.row) endGame(); }
🛠️ Now Build It For Real
You've played a working Maze Game and seen exactly how it's built. Next, build this same architecture yourself — twice, in two different tools.
🧩 Step 1 — Build It in Scratch
The "Build the Loop with Blocks" section above already shows the exact scripts — backdrop, sprites, variables, and all four key-press scripts, block by block, in Scratch's own category colors. Open a Scratch tab side-by-side and copy each script exactly; the game should come to life the same way it does here.
Open a blank Scratch project tab →Want more practice first? The Scratch Team publishes an official Maze Starter project you can open and remix directly.
Open the official Scratch "Maze Starter" project →