在 Cocos Creator 游戏开发中,UI 管理往往是项目中后期最容易“失控”的部分:弹窗覆盖错乱、动画冲突、全局导航栏被意外遮挡……随着业务迭代,这些问题会迅速消耗团队精力。本文结合项目中的一套成熟 UI 层级架构,分享一种基于 单场景 + 分层管理 的设计方案。
一、为什么选择单场景?
许多开发者习惯通过切换场景来切换界面,但这种方式会带来几个隐形成本:
- 切换开销:场景切换涉及资源释放与重新加载,容易造成卡顿。
- 状态丢失:全局数据、音乐播放、网络状态需要跨场景传递,易出错。
- 动画中断:切换场景时,任何正在播放的 UI 动画都会被迫中断。
采用 单场景(Single Scene) 架构,所有 UI 节点均挂载在同一个场景根节点下,通过控制节点的显隐、层级和动画来实现界面流转。这样既能保证流畅性,又能集中管理全局状态。
二、全局层级划分:自下而上的顺序
良好的 UI 架构首先需要明确节点间的渲染顺序。我们将整个 UI 系统划分为七个逻辑层,自下而上排列:
Top (Global) ← 最顶层,如全局加载动画、通知弹窗
Tip (Global) ← 临时提示层,如飘字、Toast 消息
PopUp ← 非模态弹窗层(可叠加)
Dialog ← 模态对话框层(带遮罩)
View ← 普通视图层(主界面内容)
Bottom (Global) ← 底部全局层,如底部导航栏、工具栏
MainScene ← 场景底层,放置背景、地图等固定内容
层级设计原则
- 下层先渲染:Cocos Creator 按照节点树顺序渲染,下层节点会先被绘制,上层节点覆盖在其上。
- 全局层独立:
Top、Tip、Bottom等全局层不随界面切换而销毁,确保通用组件始终可用。 - 模态与非模态分离:
Dialog层用于需要阻塞交互的对话框,PopUp层用于轻量级弹窗,便于统一控制遮罩和关闭行为。
三、TitleNode:独立的全局导航栏
在实际项目中,导航栏通常需要跨界面保持可见。我们使用一个独立的 TitleNode 组件来实现这一功能,它不是动态 UI 的根容器,而是位于 Top 或 View 层之上的固定组件。
TitleNode 通常包含:
- 返回按钮(用于控制 UI 栈回退)
- 标题文本(根据当前界面动态更新)
- 右侧功能按钮(如分享、设置、更多)
通过将导航栏独立于动态 UI 容器,我们可以:
- 确保弹窗不会覆盖导航栏交互区域(除非刻意设计)
- 统一控制导航栏的显隐、内容变化
- 简化界面切换时对导航栏的维护逻辑
注意:架构图中 TitleNode 下方列出的
Dialogs、Popups等并非其子节点,而是分别归属于Dialog层和PopUp层的独立容器。为了避免误解,此处特别说明。
四、动态 UI 的容器化管理
真正负责动态 UI(弹窗、对话框、临时界面)的节点,应当放置于各自所属的层级容器内。例如:
- Dialogs 容器:位于
Dialog层下,用于管理所有模态对话框。新打开的 Dialog 会被添加到该容器中,并自动位于已有 Dialog 之上,保证遮罩与交互的正确性。 - Popups 容器:位于
PopUp层下,用于管理非模态弹窗。支持同时显示多个 Popup,且彼此之间不会相互阻塞。 - 其他展示节点:可能位于
View层或Top层,用于新手引导、特殊特效等临时 UI 元素。
这种容器化管理方式带来了几点好处:
- 层级可控:只需将节点添加到正确的容器,即可自动获得正确的渲染顺序。
- 生命周期统一:所有 Dialog 或 Popup 都可以由统一的管理器负责创建、显示、关闭。
- 易于扩展:新增一种 UI 类型时,只需定义对应的容器和基类即可。
五、ActionManager:统一动画管理
UI 动画的多样性很容易导致代码重复。我们通过一个全局的 ActionManager 来统一管理所有预设动画,例如:
// ActionManager 提供的动画类型
name, scale, moveL2R, moveL2D, moveU2D,
moveL2R_FAST, moveU2D_FAST, pop, ...
- 标准化:所有弹窗、视图的进出场动画保持一致,便于统一调整风格。
- 配置化:支持普通版与快速版(FAST),满足不同场景对动画时长的需求。
- 解耦:UI 组件只需调用
ActionManager.play(node, 'moveL2R'),无需关心动画的具体实现。
六、BaseAppView:所有 UI 的通用基类
为了让每个 UI 组件都具备统一的行为,我们定义了一个 BaseAppView 基类,所有视图(包括 Dialog、Popup、普通 View)都继承自它。
class BaseAppView extends Component {
safearea_ui(); // 处理安全区适配(刘海屏、挖孔屏)
adapt_root(); // 根节点分辨率适配
pushCtrl(); // 压入控制栈(用于返回管理)
showView(); // 显示视图,自动播放进场动画
// ... 其他通用方法
}
核心功能
- 安全区适配:自动计算并调整 UI 节点位置,避免被系统状态栏或异形屏遮挡。
- 分辨率适配:根据设计分辨率与设备分辨率,自动缩放或调整布局。
- 控制栈管理:通过
pushCtrl将当前界面压入栈中,配合返回按钮实现统一的返回逻辑(关闭当前界面或返回上一级)。
七、总结与优势
这套单场景 UI 层级架构已在多个项目中落地,取得了以下效果:
- 层级清晰:自下而上的分层配合容器化管理,让 UI 的渲染顺序一目了然。
- 复用性高:
BaseAppView和ActionManager将通用逻辑集中,减少重复代码。 - 扩展性强:新增 UI 只需继承
BaseAppView,并将其添加到对应的容器层,无需关心层级细节。 - 交互稳定:导航栏与动态 UI 解耦,避免了弹窗遮挡按钮的常见问题。
当然,没有一种架构能适用于所有项目。实际应用中,你可以根据游戏规模适当调整分层粒度,或引入懒加载机制来优化性能。但无论如何,提前规划好 UI 层级永远是避免后期混乱的最佳手段。