Minimal Frogger (Unity / C#)

The step-6 project in overview-arcade-classics-as-learning-projects. It returns to discrete grid movement (like Snake) but sets it against a world that moves continuously, which is what makes timing the core skill. It covers the canon reference’s list for Frogger (see source-classic-games-canon): grid movement, moving hazards, timing, and level boundaries.

Original project inspired by a recognisable pattern — not a clone.

Files

ScriptResponsibilityKey wiki concept
Hazard.csA car or log that slides at fixed velocity and despawns off-screenunity-transform
Lane.csSpawns hazards from one edge on a timermonobehaviour-lifecycle
FrogController.csDiscrete hop + boundary clamp; squash / drown / ride logicunity-input, unity-collider2d-and-triggers
FroggerGame.csBuilds rows from data, maps height → lane type, owns score/livescsharp-enums, unity-gamemanager-pattern

What is new at this step

  • Grid hop against continuous motion. The frog moves one row/column per key press (GetKeyDown), but cars and logs move every frame. The interesting decisions are when to hop, not just where — that is the timing skill.
  • Two hazard rules from one structure. A Road lane kills on contact; a River lane kills unless the frog is on a log, which then carries it. Both are just lanes with a type; the frog resolves the rule each frame in EvaluateLane.
  • Data-driven layout. FroggerGame builds the board from a LaneDef[] you fill in the Inspector (type, speed, spawn interval, bottom row up). The safe start and goal rows are added automatically.
  • Level boundaries. The frog is clamped horizontally, and being carried off the screen edge by a log is fatal — boundaries are part of the challenge.

Scene setup (about 12 minutes)

  1. New 2D scene, Main Camera set to Orthographic (size ~5).
  2. Add two user layers: Vehicle and Log (Edit → Project Settings → Tags and Layers).
  3. Car prefab: a square/rectangle sprite, layer Vehicle, with a Box Collider 2D and the Hazard script. Make it a prefab; delete the scene copy.
  4. Log prefab: a wide sprite (scale x to ~2.5), layer Log, with a Box Collider 2D and the Hazard script. Make it a prefab.
  5. Frog: a small sprite at the origin with the FrogController script. Set Vehicle Mask to the Vehicle layer and Log Mask to the Log layer. (No collider needed — it uses overlap queries.)
  6. Game: empty GameObject Game, add FroggerGame, assign the Car Prefab, Log Prefab, and Frog, then fill Lanes bottom-up, e.g.:
    • Road, speed 3, interval 1.6
    • Road, speed -4, interval 1.3
    • Road, speed 2.5, interval 1.8
    • Safe, 0, 0 (a median strip)
    • River, speed 2, interval 2.0
    • River, speed -2.5, interval 2.2
  7. Press Play. WASD or arrows hop one cell at a time. Cross the roads, ride the logs across the river, and reach the top row to score. Getting squashed, drowning, or drifting off-screen costs a life.

Why timing is the whole game

Snake’s grid asked “which way?“. Frogger’s grid asks “which way, and when?“. Because the frog is discrete and the traffic is continuous, every safe move depends on reading gaps and committing at the right moment. Tuning lane speeds and spawn intervals is tuning the difficulty directly — see game-feel and smooth-learning-curves.

Extension ladder

These point toward step 7 (Pac-Man-lite: tilemaps, pathfinding, AI state machines):

  1. On-screen score and lives — replace Debug.Log with UI/TMP text.
  2. Home slots — several goal bays at the top that each fill once; win when all are filled (a small win-condition system).
  3. Snap to a tile grid — round the frog’s x to fixed columns and lay lanes out with unity-tilemap; the bridge to maze games.
  4. Pool the hazards — reuse the object-pool-pattern from step 4 instead of Instantiate/Destroy.
  5. Timer pressure and turtles that submerge — add a countdown and periodic “logs” that sink, deepening the timing read.

Source files

4 items under this folder.