UI Systems
Unity 的 UI 技术栈涵盖经典 Unity UI(uGUI)与现代 UI Toolkit,以及 Canvas、CanvasScaler、EventSystem——构建菜单、HUD 与各类界面所需的核心工具。理解锚点布局、合批与事件流,能帮 UI 程序与设计师在多分辨率适配、运行时性能与可维护性之间做出正确选择。
想象一下...
Canvas 是挡在屏幕前的空白纸——所有 UI 元素都在上面。CanvasScaler 是尺子,分辨率变化(1080p 到手机)时缩放这张纸。EventSystem 是虚拟鼠标,决定点了哪个元素。三者缺一,UI 就会不显示、不缩放或不响应点击。
概念详解
Canvas 是所有 UI 的根容器。三种渲染模式:
Screen Space - Overlay
(始终在游戏之上,与相机无关)、
Screen Space - Camera
(经特定相机渲染,受深度/后期影响),以及
World Space
(场景中的 3D 对象——世界内屏幕、角色头顶血条)。
CanvasScaler 解决多分辨率。
Scale With Screen Size
是常用模式:在 Reference Resolution(1920×1080)下设计,scaler 适配真实屏幕。
Match(0=宽,1=高,0.5=平均)决定优先哪条轴。
EventSystem 是处理所有 UI 输入的单例:点击、触摸、手柄。 用 Raycaster(Canvas 上的 GraphicRaycaster,World Space 用 PhysicsRaycaster) 找悬停/选中元素。场景中必须 恰好一个 EventSystem——多了会冲突。
Unity 2021+ 起,UI Toolkit 是更新的栈,借鉴 Web 思路 (UXML 布局、USS 样式如 HTML/CSS)。复杂 UI 性能优于 uGUI,但与 3D 玩法集成更难。 游戏内运行时 UI 仍以 uGUI 更常见。
标准 Unity UI 层级
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 始终叠在场景之上。HUD、背包、主菜单。不受摄像机影响。
Screen Space - Camera
通过指定 Camera 渲染。可对 UI 做后处理(blur、bloom)。
World Space
UI 是 3D 对象。血条、游戏内屏幕、VR UI。需要 EventSystem + camera raycast。
动手步骤
创建基础 Canvas
GameObject → UI → Canvas。Unity 会添加 Canvas + CanvasScaler + GraphicRaycaster + EventSystem。
配置 CanvasScaler
UI Scale Mode → Scale With Screen Size。Reference Resolution → 1920×1080(或你的目标)。Match → 0.5。
使用 RectTransform
UI 用 RectTransform 而非 Transform。Anchor 预设(右上、全屏拉伸…)是响应式布局的关键。
多 Canvas 设置 Sorting Order
Canvas → Sort Order:数字越大画在越上面。提示在背包之上,对话框在 HUD 之上。
拆分 Canvas 减少重批
每个 canvas 单独批处理。静态 UI(背景)放独立 Canvas,避免动态 UI 弄脏整批。
交互模拟器
观察 CanvasScaler——调整屏幕尺寸,看 UI 如何随之缩放。
Game Menu
Scale: 1.00 | Reference: 1920×1080
代码示例
基础用脚本更新 UI——血条、分数文字、显示/隐藏面板。
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
}
}代码示例
进阶World Space UI——角色头顶血条,始终面向相机。
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);
}
}📌 快速记忆
- ▸Canvas Overlay:不受相机影响
- ▸CanvasScaler:Scale With Screen Size → Reference 1920×1080
- ▸场景中只能有 1 个 EventSystem——多了会出 bug
- ▸拆分静态/动态 Canvas,避免昂贵的重批
- ▸World Space UI 用 LateUpdate,以便在物理之后跟随
⚠️ 常见错误
❌ Button 收不到点击
缺少 EventSystem,或 GraphicRaycaster 被禁用
✅ 确保存在 EventSystem,且 Canvas 有 GraphicRaycaster
❌ PC 与手机上 UI 观感不同
CanvasScaler 未配置
✅ Scale With Screen Size + Reference 1920×1080 + Match 0.5