UI Systems
Unity's UI stack covers classic Unity UI (uGUI) and modern UI Toolkit, plus Canvas, CanvasScaler, and EventSystem — the tools for menus, HUDs, and screens.
Imagine...
A Canvas is a blank sheet in front of the screen — every UI element lives on it. A CanvasScaler is the ruler that shrinks or grows that sheet when the resolution changes (1080p down to a phone). An EventSystem is a virtual mouse that decides which element was clicked. Missing any of the three means UI that does not show, does not scale, or does not click.
The concept in detail
A Canvas is the root container for all UI. Three
render modes:
Screen Space - Overlay
(always on top of the game, camera-independent),
Screen Space - Camera
(rendered through a specific camera, affected by depth/post-process), and
World Space
(a 3D object in the scene — in-world screens, health bars over characters).
CanvasScaler solves multi-resolution.
Scale With Screen Size
is the usual mode: you design at a Reference Resolution (1920×1080), and the scaler fits the
real screen. Match (0=width, 1=height, 0.5=average) picks which axis to prioritize.
EventSystem is the singleton that handles all UI input: clicks, touch, gamepad. It uses a Raycaster (GraphicRaycaster on Canvas, PhysicsRaycaster for World Space) to find the hovered/selected element. There must be exactly one EventSystem in the scene — more than one conflicts.
From Unity 2021+, UI Toolkit is the newer stack built on web ideas (UXML layout, USS styling like HTML/CSS). It outperforms uGUI on complex UI, but integrating with 3D gameplay is harder. uGUI is still the common choice for in-game runtime UI.
A standard Unity UI hierarchy
uGUI (Scene Hierarchy)
📁 Canvas(+ CanvasScaler)
├ 📁 Panel
├ Image(background)
├ Text (TMP)
└ Button
└ Text (TMP)
└ 📁 HUD
├ Slider(health)
└ RawImage(minimap)
📁 EventSystem
Render Modes
Screen Space - Overlay
UI always draws on top of the scene. HUD, inventory, main menu. Unaffected by the camera.
Screen Space - Camera
Renders through a specific Camera. Allows post-processing on UI (blur, bloom).
World Space
UI is a 3D object. Health bars, in-game screens, VR UI. Needs EventSystem + camera raycast.
Hands-on steps
Create a basic Canvas
GameObject → UI → Canvas. Unity adds Canvas + CanvasScaler + GraphicRaycaster + EventSystem.
Configure CanvasScaler
UI Scale Mode → Scale With Screen Size. Reference Resolution → 1920×1080 (or your target). Match → 0.5.
Use RectTransform
UI uses RectTransform instead of Transform. Anchor presets (top-right, stretch full screen...) are the key to responsive layout.
Set Sorting Order for multiple Canvases
Canvas → Sort Order: higher numbers draw on top. Tooltips above inventory, dialogs above HUD.
Split Canvases to reduce rebatching
Each canvas batches separately. Put static UI (background) on its own Canvas so dynamic UI does not dirty the whole batch.
Interactive simulator
Watch CanvasScaler work — resize the screen and see the UI scale with it.
Game Menu
Scale: 1.00 | Reference: 1920×1080
Code example
BasicUpdate UI from script — health bar, score text, show/hide panels.
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class HUDController : MonoBehaviour
{
[Header("Health")]
public Slider healthSlider;
public TMP_Text healthText;
[Header("Score")]
public TMP_Text scoreText;
[Header("Panels")]
public GameObject menuPanel;
public GameObject hudPanel;
public void UpdateHealth(float current, float max)
{
healthSlider.value = current / max;
healthText.text = $"{Mathf.RoundToInt(current)}/{Mathf.RoundToInt(max)}";
// Tint when HP is low
healthSlider.fillRect.GetComponent<Image>().color =
current / max < 0.3f ? Color.red : Color.green;
}
public void ShowMenu(bool show)
{
menuPanel.SetActive(show);
hudPanel.SetActive(!show);
Time.timeScale = show ? 0f : 1f; // Pause while the menu is open
}
public void UpdateScore(int score)
{
scoreText.text = score.ToString("N0"); // "1,280" format
}
}Code example
AdvancedWorld Space UI — a health bar over a character that always faces the camera.
using UnityEngine;
using UnityEngine.UI;
// Attach to a World Space Canvas — HP bar over a character
public class WorldSpaceHealthBar : MonoBehaviour
{
public Slider slider;
public Vector3 offset = new Vector3(0, 2.5f, 0);
public Transform target;
Camera cam;
void Start() => cam = Camera.main;
void LateUpdate()
{
if (target == null) return;
// Follow the character + offset
transform.position = target.position + offset;
// Always face the camera (billboard)
transform.LookAt(transform.position + cam.transform.rotation * Vector3.forward,
cam.transform.rotation * Vector3.up);
}
public void SetHealth(float current, float max)
{
slider.value = current / max;
// Hide when HP is full
gameObject.SetActive(current < max);
}
}📌 Quick recap
- ▸Canvas Overlay: not affected by the camera
- ▸CanvasScaler: Scale With Screen Size → Reference 1920×1080
- ▸Only 1 EventSystem in the scene — more causes bugs
- ▸Split static/dynamic Canvases to avoid expensive rebatching
- ▸LateUpdate for World Space UI so it follows after physics
⚠️ Common mistakes
❌ The Button does not receive clicks
Missing EventSystem, or GraphicRaycaster is disabled
✅ Ensure an EventSystem exists and the Canvas has a GraphicRaycaster
❌ UI looks different on PC vs phone
CanvasScaler is not configured
✅ Scale With Screen Size + Reference 1920×1080 + Match 0.5