Game UI and Score System
Canvas, UI elements, and simple game state management.
Step 1: Create Canvas and Event System
Choose GameObject > UI > Canvas. Unity also creates an EventSystem, which is required for buttons and pointer input. Set Render Mode to Screen Space - Overlay for a HUD that draws on top of gameplay.
On Canvas Scaler, choose Scale With Screen Size and a reference resolution such as 1920x1080. Set Match to 0.5 for balanced scaling on phones and desktops. Anchor score text to the top center with a RectTransform preset so it stays readable when resolution changes.
Step 2: Score Text with TextMeshPro
Add UI > Text - TextMeshPro for sharp text at any resolution. Import TMP Essentials on first use. Name the object ScoreText, set font size around 48, and center the alignment.
Create ScoreManager.cs on an empty GameSystems object. Expose a TextMeshProUGUI reference and a public AddScore(int amount) method that updates both the score variable and the label. Wire the reference in the Inspector and test AddScore in Play mode.
Step 3: Coin Pickup with Triggers
Make a Coin Prefab with a sprite, Circle Collider 2D (Is Trigger = true), and a CoinPickup script. In OnTriggerEnter2D, check CompareTag("Player"), call ScoreManager.AddScore(10), play a sound or particle, then Destroy(gameObject).
The player needs a Rigidbody2D and a non-trigger collider. If pickup fails, verify Is Trigger on the coin, the Player tag, and that layers are not blocking interaction incorrectly.
Step 4: Game Over and Restart
Build a GameOver panel with a semi-transparent background, title text, and a Restart button. Hide it in Start with SetActive(false). GameManager should expose TriggerGameOver that sets state, shows the panel, and sets Time.timeScale = 0f.
Restart must reset timeScale to 1f and reload the scene with SceneManager.LoadScene. Connect the button OnClick to the restart method in the Inspector. Add PlayerHealth with TakeDamage and call GameOver when health reaches zero.
Step 5: Buttons and Pause Menu
Configure Button transitions and add click audio if desired. On Game Over, disable PlayerController so input does not move the character under the panel. Optionally open a pause menu with Escape when state is Playing.
Use EventSystem.SetSelectedGameObject on the restart button so gamepad users can confirm without a mouse. Keep touch targets at least 44–48 px tall for mobile.
Step 6: High Score and Polish
Store high score with PlayerPrefs.SetInt after game over when the current score is higher than the saved value. Display best score on the HUD at start with PlayerPrefs.GetInt.
Add SafeArea handling for notched phones by adjusting root HUD anchors from Screen.safeArea. You now have a minimal playable loop: score, damage, game over, restart, and optional pause — ready for a portfolio build.
FAQ
TextMeshPro or legacy UI Text?
Use TextMeshPro for all new UI. It renders sharply with SDF, supports outlines and rich text, and is the recommended Unity UI text solution going forward.
What does timeScale = 0 do?
It pauses gameplay physics and time-based Update logic. UI can still animate if you use unscaled time. Always reset timeScale to 1 before reloading a scene or gameplay stays frozen.
Is a Singleton okay for ScoreManager?
For tutorials and small prototypes, a simple Singleton is fine for quick access. In larger projects, prefer events or dependency injection to reduce hidden coupling and improve testability.