乌啦呀哈呀哈乌啦!

欢迎光临,这里是喵pass的个人博客,希望有能帮到你的地方

0%

游戏UI框架设计

游戏 UI 中的“框架”通常指两类东西:负责显示界面的 UI 系统,以及负责组织界面代码的架构框架。

以 Unity 为例,uGUI、UI Toolkit 属于第一类;MVC、MVP、MVVM,以及窗口管理、页面导航、数据绑定等机制属于第二类。
它们可以组合使用,例如:

用 uGUI 制作界面,用 MVP 组织代码,再用 UIManager 管理窗口的打开、关闭和层级。

UI系统

UI 系统 核心方式 常见用途 主要特点
uGUI Canvas + GameObject + Component 游戏 HUD、背包、商店、弹窗 与 Unity 场景、Prefab、动画系统结合紧密
UI Toolkit VisualElement + UXML + USS 编辑器工具、菜单、设置、列表型界面 文档结构、样式与逻辑分离
IMGUI 在 OnGUI() 中通过代码绘制 简单调试界面、旧编辑器工具 写起来直接,但不适合作为复杂游戏 UI 的主系统
FairyGUI 等第三方方案 专用编辑器 + 对应运行时 界面量大、依赖 UI 设计协作的项目 强调界面制作、组件复用、过渡动画等完整工作流

这里的选择决定了“界面怎么制作和渲染”,但不会自动解决“业务逻辑怎么组织”。

代码框架

无论用哪种 UI 系统,都会遇到同一个问题:

用户点了按钮,谁处理操作?数据变了,谁更新界面?

MVC、MVP、MVVM 就是在回答这个问题。

架构 主要角色 界面如何更新 适合情况
MVC Model、View、Controller 由 Controller 或模型通知机制推动 流程简单、团队约定清晰
MVP Model、View、Presenter Presenter 显式调用 View uGUI 项目、希望逻辑清晰且容易测试
MVVM Model、View、ViewModel 通过绑定或状态通知更新 表单、列表、状态较多的界面
单向数据流 State、Action、Reducer/处理器、View 操作更新状态,界面读取状态 状态组合复杂、需要追踪变化的界面
这些名字不是自动就能带来良好设计。关键在于:显示、交互协调和业务规则是否有明确边界。

项目设计

MVC、MVP、MVVM 只解决代码组织的一部分。游戏项目还需要处理以下问题。

能力 Unity 中的典型问题
窗口管理 同一个窗口能否重复打开?关闭后销毁还是缓存?
生命周期 什么时候绑定事件、刷新数据、播放动画、释放资源?
分层 HUD、普通页面、弹窗、加载遮罩谁在上面?
导航 返回键关闭弹窗,还是回到上一个页面?
资源加载 Prefab 从哪里加载?异步加载如何避免重复?
数据同步 金币变化后,哪些可见页面需要刷新?
列表复用 几百个背包物品如何避免生成几百套复杂控件?
输入管理 弹窗打开后,下面的页面还能否被点击?
分辨率适配 安全区域、横竖屏、锚点、长文本如何处理?
异步取消 窗口关闭后,请求结果是否还会写入控件?
其中最容易被低估的是生命周期和异步处理。

假设玩家打开排行榜,界面开始请求数据,然后玩家马上关闭它:

打开排行榜
↓
开始网络请求
↓
关闭排行榜
↓
请求返回

此时如果直接执行:rankText.text = result;
可能出现对象已经销毁、数据更新到下一次打开的界面,或旧请求覆盖新请求的情况。
框架需要明确约定:关闭时取消请求,或在结果返回时检查本次打开是否仍然有效。

窗口生命周期

一种常见设计是:

创建
↓
初始化
↓
打开
↓
显示
↓
关闭
↓
隐藏并缓存 / 销毁

假如约定以下方法:

1
2
3
4
5
6
OnCreate()
OnOpen(args)
OnShow()
OnHide()
OnClose()
OnDestroy()

这些名字的具体含义由框架决定,并不是 Unity 内置生命周期。
还要与 Unity 的 Awake、OnEnable、OnDisable、OnDestroy 区分。例如隐藏一个缓存窗口,只会使它停用;下一次打开时,Awake() 不会重新执行。

分层与导航

常见层级可以是:

HUD
Page
Popup
Loading
Toast

但“画在上面”和“阻止下面接收输入”是两个问题。一个透明遮罩即使视觉上位于最上层,也需要正确配置射线或输入处理,才能阻止点击穿透。

导航则适合使用页面栈:

主界面 → 背包 → 物品详情

返回时:

物品详情 → 背包 → 主界面

Toast、加载遮罩和长期显示的 HUD 通常不应该全部放进同一套返回栈。

缓存与列表虚拟化

这两者容易混淆:

  • 窗口缓存:关闭背包后保留整个背包实例,下次直接复用。
  • 对象池:反复使用物品格子,减少创建和销毁。
  • 列表虚拟化:只保留可视区域附近的格子,根据滚动位置展示不同数据。
    有 1000 件物品时,即使通过对象池创建了 1000 个格子,它们仍可能带来大量布局和渲染成本。虚拟化解决的是“同时存在多少个显示单元”的问题。