Beginner 2D route: move, collect, score (Unity / C#)
Six small scripts that build one top-down 2D scene step by step: a player who
moves with physics, coins that award score through a single GameManager,
a spawner that places coins from a prefab, and a little pickup feedback.
The folder is called ebook for historical reasons: the scripts were first
written to accompany a draft student ebook. They are now simply the beginner
2D route for the wiki, and each one is linked from the wiki page that
explains its idea. They are deliberately plain (Inspector references, no
singleton, no events) so that each step adds one new idea.
Files and suggested order
| Order | Script | What it demonstrates | Wiki page |
|---|---|---|---|
| 1 | TopDownPlayerMovement.cs | Read input in Update, apply it to a Rigidbody2D in FixedUpdate; normalised input so diagonals are not faster | unity-rigidbody2d, unity-input, monobehaviour-lifecycle |
| 2 | PlayerHealth.cs | Private state set up in Start and changed only through a public method (TakeDamage), with a floor at zero | monobehaviour-lifecycle, unity-gamemanager-pattern |
| 3 | GameManager.cs | One object owns the score; other scripts ask it to change through AddScore, which rejects invalid amounts | unity-gamemanager-pattern, unity-object-communication |
| 4 | CoinPickup.cs | A trigger pickup: tag check with CompareTag, one call to the GameManager, then remove the coin | unity-collider2d-and-triggers |
| 5 | PickupSpawner.cs | Instantiate a coin prefab at each spawn point, skip missing points, parent the clones to keep the Hierarchy tidy, and pass each coin the scene’s GameManager | unity-prefabs-scripting, unity-prefabs |
| 6 | CoinPickupFeedback.cs | Pickup feedback: hide the sprite, play particles and a sound, then destroy the coin after a short delay | unity-audiosource, unity-particle-system-scripting, game-feel |
Unity requires one MonoBehaviour per file with a matching file name, so copy
the .cs files into your project’s Assets/Scripts/ folder unchanged.
Scene setup (about 10 minutes)
- New 2D scene. Keep the Main Camera orthographic.
- Player: create a square sprite named
Player, set its Tag toPlayer, and add Rigidbody2D (Body Type Dynamic, Gravity Scale 0, Freeze Rotation Z ticked), a Box Collider 2D,TopDownPlayerMovementandPlayerHealth. - GameManager: create an empty GameObject named
GameManagerand addGameManager. - Coin: create a small circle sprite named
Coin. Add a Circle Collider 2D with Is Trigger ticked, thenCoinPickup. Drag theGameManagerobject into its Game Manager field. Press Play and walk over it: the Console should logScore: 10. - Prefab and spawner: drag
Coininto the Project window to make a prefab, then delete the scene copy. Create a few empty GameObjects as spawn points and an emptyPickupsobject as a parent. AddPickupSpawnerto another empty object and fill Coin Prefab, Spawn Points, Pickup Parent and Game Manager. A prefab asset cannot keep a reference to an object in the scene, so the spawned coins arrive with an empty Game Manager field. The spawner fills it by callingCoinPickup.SetGameManageron each new coin. - Feedback (optional): open the coin prefab, add a child Particle
System (untick Play On Awake) and an AudioSource on the coin
(untick Play On Awake, assign a short clip). Add
CoinPickupFeedback, fill its three fields, and drag it into the coin’s Feedback field.
Input setting
The movement script uses the legacy Input Manager (Input.GetAxisRaw), as the
unity-input page does. If Unity reports an InvalidOperationException
about UnityEngine.Input when you press Play, your project is set to the new
Input System only: open Edit → Project Settings → Player → Other Settings →
Active Input Handling, choose Both, and let the Editor restart. To port the
script to the new system, see unity-input-system.
Things to notice
- Two clocks. Input is read every frame in
Update; the body is moved on the physics step inFixedUpdate. Turn on Interpolate on the player’s Rigidbody2D if the camera follows it and it jitters (see unity-rigidbody2d). - One owner of the score.
CoinPickupnever touchesscore; it asks theGameManager. Break the coin’s reference on purpose and read the error. - Collect once.
CoinPickupsets acollectedflag before awarding score. Without it, a coin that lingers for its feedback, or a player with two colliders, could score twice. - Feedback length. The AudioSource is on the coin, and the coin is destroyed 0.5 seconds after pickup, so a longer clip is cut off. Keep the clip short, lengthen the delay, or play the sound from a central source instead (see unity-audiosource).
- Class names. These scripts use the plain names
GameManager,PlayerHealthandCoinPickup. Do not copy them into a project that already has classes with those names.
What to try next
- Hazard: add a trigger that calls
PlayerHealth.TakeDamage(1)on the player (see unity-collider2d-and-triggers). - On-screen score: show
GameManager.GetScore()in a TextMeshPro label, then change theGameManagerto raise aScoreChangedevent so the label stops polling (see “Singleton vs events” in unity-gamemanager-pattern). - Respawn wave: track spawned coins in a
List<GameObject>and spawn a new set when the list is empty (see unity-prefabs-scripting). - Feel: swap
GetAxisRawforGetAxisand compare how movement starts and stops (see game-feel).