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

OrderScriptWhat it demonstratesWiki page
1TopDownPlayerMovement.csRead input in Update, apply it to a Rigidbody2D in FixedUpdate; normalised input so diagonals are not fasterunity-rigidbody2d, unity-input, monobehaviour-lifecycle
2PlayerHealth.csPrivate state set up in Start and changed only through a public method (TakeDamage), with a floor at zeromonobehaviour-lifecycle, unity-gamemanager-pattern
3GameManager.csOne object owns the score; other scripts ask it to change through AddScore, which rejects invalid amountsunity-gamemanager-pattern, unity-object-communication
4CoinPickup.csA trigger pickup: tag check with CompareTag, one call to the GameManager, then remove the coinunity-collider2d-and-triggers
5PickupSpawner.csInstantiate 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 GameManagerunity-prefabs-scripting, unity-prefabs
6CoinPickupFeedback.csPickup feedback: hide the sprite, play particles and a sound, then destroy the coin after a short delayunity-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)

  1. New 2D scene. Keep the Main Camera orthographic.
  2. Player: create a square sprite named Player, set its Tag to Player, and add Rigidbody2D (Body Type Dynamic, Gravity Scale 0, Freeze Rotation Z ticked), a Box Collider 2D, TopDownPlayerMovement and PlayerHealth.
  3. GameManager: create an empty GameObject named GameManager and add GameManager.
  4. Coin: create a small circle sprite named Coin. Add a Circle Collider 2D with Is Trigger ticked, then CoinPickup. Drag the GameManager object into its Game Manager field. Press Play and walk over it: the Console should log Score: 10.
  5. Prefab and spawner: drag Coin into the Project window to make a prefab, then delete the scene copy. Create a few empty GameObjects as spawn points and an empty Pickups object as a parent. Add PickupSpawner to 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 calling CoinPickup.SetGameManager on each new coin.
  6. 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 in FixedUpdate. Turn on Interpolate on the player’s Rigidbody2D if the camera follows it and it jitters (see unity-rigidbody2d).
  • One owner of the score. CoinPickup never touches score; it asks the GameManager. Break the coin’s reference on purpose and read the error.
  • Collect once. CoinPickup sets a collected flag 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, PlayerHealth and CoinPickup. Do not copy them into a project that already has classes with those names.

What to try next

  1. Hazard: add a trigger that calls PlayerHealth.TakeDamage(1) on the player (see unity-collider2d-and-triggers).
  2. On-screen score: show GameManager.GetScore() in a TextMeshPro label, then change the GameManager to raise a ScoreChanged event so the label stops polling (see “Singleton vs events” in unity-gamemanager-pattern).
  3. Respawn wave: track spawned coins in a List<GameObject> and spawn a new set when the list is empty (see unity-prefabs-scripting).
  4. Feel: swap GetAxisRaw for GetAxis and compare how movement starts and stops (see game-feel).

Source files

6 items under this folder.