Cocos Creator 单场景 UI 层级架构设计实践

6 阅读5分钟

在 Cocos Creator 游戏开发中,UI 管理往往是项目中后期最容易“失控”的部分:弹窗覆盖错乱、动画冲突、全局导航栏被意外遮挡……随着业务迭代,这些问题会迅速消耗团队精力。本文结合项目中的一套成熟 UI 层级架构,分享一种基于 单场景 + 分层管理 的设计方案。

一、为什么选择单场景?

许多开发者习惯通过切换场景来切换界面,但这种方式会带来几个隐形成本:

  • 切换开销:场景切换涉及资源释放与重新加载,容易造成卡顿。
  • 状态丢失:全局数据、音乐播放、网络状态需要跨场景传递,易出错。
  • 动画中断:切换场景时,任何正在播放的 UI 动画都会被迫中断。

采用 单场景(Single Scene) 架构,所有 UI 节点均挂载在同一个场景根节点下,通过控制节点的显隐、层级和动画来实现界面流转。这样既能保证流畅性,又能集中管理全局状态。

二、全局层级划分:自下而上的顺序

良好的 UI 架构首先需要明确节点间的渲染顺序。我们将整个 UI 系统划分为七个逻辑层,自下而上排列:

Top (Global)      ← 最顶层,如全局加载动画、通知弹窗
Tip (Global)      ← 临时提示层,如飘字、Toast 消息
PopUp             ← 非模态弹窗层(可叠加)
Dialog            ← 模态对话框层(带遮罩)
View              ← 普通视图层(主界面内容)
Bottom (Global)   ← 底部全局层,如底部导航栏、工具栏
MainScene         ← 场景底层,放置背景、地图等固定内容

层级设计原则

  • 下层先渲染:Cocos Creator 按照节点树顺序渲染,下层节点会先被绘制,上层节点覆盖在其上。
  • 全局层独立TopTipBottom 等全局层不随界面切换而销毁,确保通用组件始终可用。
  • 模态与非模态分离Dialog 层用于需要阻塞交互的对话框,PopUp 层用于轻量级弹窗,便于统一控制遮罩和关闭行为。

三、TitleNode:独立的全局导航栏

在实际项目中,导航栏通常需要跨界面保持可见。我们使用一个独立的 TitleNode 组件来实现这一功能,它不是动态 UI 的根容器,而是位于 TopView 层之上的固定组件。

TitleNode 通常包含:

  • 返回按钮(用于控制 UI 栈回退)
  • 标题文本(根据当前界面动态更新)
  • 右侧功能按钮(如分享、设置、更多)

通过将导航栏独立于动态 UI 容器,我们可以:

  • 确保弹窗不会覆盖导航栏交互区域(除非刻意设计)
  • 统一控制导航栏的显隐、内容变化
  • 简化界面切换时对导航栏的维护逻辑

注意:架构图中 TitleNode 下方列出的 DialogsPopups 等并非其子节点,而是分别归属于 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 层级架构已在多个项目中落地,取得了以下效果:

  1. 层级清晰:自下而上的分层配合容器化管理,让 UI 的渲染顺序一目了然。
  2. 复用性高BaseAppViewActionManager 将通用逻辑集中,减少重复代码。
  3. 扩展性强:新增 UI 只需继承 BaseAppView,并将其添加到对应的容器层,无需关心层级细节。
  4. 交互稳定:导航栏与动态 UI 解耦,避免了弹窗遮挡按钮的常见问题。

当然,没有一种架构能适用于所有项目。实际应用中,你可以根据游戏规模适当调整分层粒度,或引入懒加载机制来优化性能。但无论如何,提前规划好 UI 层级永远是避免后期混乱的最佳手段。