Minimal Asteroids (Unity / C#)
The step-5 project in overview-arcade-classics-as-learning-projects, and the first one where the player’s craft has momentum rather than direct control. It introduces the skills the canon reference (see source-classic-games-canon) lists for Asteroids: vector movement, screen wrapping, spawning, and object splitting (plus inertia).
Original project inspired by a recognisable pattern — not a clone.
Files
| Script | Responsibility | Key wiki concept |
|---|---|---|
ScreenWrap2D.cs | Reusable: wraps any object to the opposite edge | unity-transform |
ShipController.cs | Rotate, thrust into a velocity vector, drag, fire, collide | unity-input, steering-behaviours |
Bullet.cs | Short-lived projectile; hits an asteroid and triggers its split | unity-collider2d-and-triggers |
Asteroid.cs | Drifts, carries a Size tier, reports hits | csharp-enums |
AsteroidsGame.cs | Spawns waves, performs the split, owns score/lives/state | csharp-collections, unity-gamemanager-pattern |
ArcadeHud.cs (in ../shared/) | Shared on-screen HUD: a status line plus a timed centre message, drawn with TextMeshPro | ui-design, game-interface-types |
What is new at this step
- Inertial vector movement. Thrust adds to a
velocityvector instead of setting position. The ship keeps drifting after you let go, and turning only changes where thrust will push next — not where you are already heading. This is the same vector-integration idea behind steering-behaviours, stripped to its simplest form. - Screen wrapping.
ScreenWrap2Dis written once as its own component and reused on the ship, the asteroids, and (optionally) the bullets. Wrapping inLateUpdatemeans it runs after movement each frame. - Spawning and recursive splitting.
AsteroidsGame.OnAsteroidHitis the highlight: a Large asteroid becomes two Mediums, each Medium becomes two Smalls, and Smalls simply vanish. Centralising the spawn in the field keeps the recursion in one readable place.
Scene setup (about 12 minutes)
- New 2D scene, Main Camera set to Orthographic.
- Add a user layer
Asteroids(Edit → Project Settings → Tags and Layers). - Asteroid prefab: a roughly round sprite (a square is fine), layer
Asteroids, with a Circle Collider 2D, the
Asteroidscript, and aScreenWrap2Dcomponent. Make it a prefab; delete the scene copy. - Bullet prefab: a small dot sprite with the
Bulletscript. (AddScreenWrap2Dtoo if you want wrapping shots.) Make it a prefab. - Ship: a triangle-ish sprite pointing up, at the origin. Add
ShipControllerandScreenWrap2D. Assign the Bullet Prefab and set Asteroid Mask to the Asteroids layer. (The ship needs no collider — it checks for asteroids with an overlap query.) - Game: empty GameObject
Game, addAsteroidsGame, and assign the Asteroid Prefab and the Ship. - HUD: copy
../shared/ArcadeHud.csinto the project as well. Add GameObject → UI → Text - TextMeshPro (click Import TMP Essentials the first time). Unity also creates a Canvas (leave it on Screen Space - Overlay) and an EventSystem. Name the textStatusTextand anchor it to the top-left; duplicate it asMessageText, anchor it to the centre, and set its alignment to centre. AddArcadeHudto the Canvas, drag both texts into its Status Text and Message Text fields, then drag the Canvas into the Hud field onGame. (Leave Hud empty and messages print to the Console instead.) - Press Play. A/D or left/right rotate, W/up thrusts, Space fires. Shooting a large rock splits it; clearing the field starts a busier wave; colliding with a rock costs a life (with a brief invulnerable respawn). Score, lives, and wave show on screen.
Why momentum changes the design
Direct-control games (Pong, Snake) ask “where do I want to be?“. Asteroids asks
“what is my velocity, and how do I manage it?“. That single change — integrating a
velocity vector instead of setting position — is why the ship feels so different
and why aiming while drifting is the core skill. It is worth tuning
thrustPower, maxSpeed, and drag to feel the trade-off; see game-feel.
Extension ladder
These point toward step 6 (Frogger) and step 7 (Pac-Man-lite):
- Pool the bullets and asteroids — swap Instantiate/Destroy for the object-pool-pattern from step 4 and check the unity-profiler.
- Thrust visuals and screen shake — exhaust flame, fire recoil; minimal game-feel.
- Saucer enemy — a periodic UFO that crosses and shoots back (timer-driven, like the invader firing in step 4).
- Momentum-aware shots — add the ship’s velocity to the bullet velocity and feel how it changes aiming.