总览
Common UI 不是“UMG 里多几个按钮”。UE5.8 源码里的 CommonUI 插件默认不启用,包含 CommonUI、CommonInput、CommonUIEditor 三个模块,插件可携带内容,并依赖 Enhanced Input。它真正解决的是游戏 UI 的四个老问题:页面进出场没有生命周期、手柄返回键到处乱绑、键鼠/手柄/触摸提示不统一、打开菜单后 gameplay 输入是否应该被挡住说不清。
一句话心智模型:Common UI 用 UCommonActivatableWidget 表示一个可激活页面,用 Stack/Queue 管页面层级,用 UCommonUIActionRouterBase 把输入先送到当前激活树,用 UCommonInputSubsystem 判断当前设备,再让 UCommonActionWidget 和 UCommonBoundActionBar 显示正确按键提示。
专题分篇目录
| 篇章 | 你会学到什么 | 读完能做什么 |
|---|---|---|
| 一 | 先跑通第一个菜单 | 启用插件、配置 ViewportClient、创建 RootLayout、Push 主菜单 |
| 二 | Activatable Widget 生命周期 | 分清 Construct、Activate、Deactivate、Destruct、返回键和焦点 |
| 三 | Stack、Queue 和 UI Layer | 搭主菜单、弹窗、Toast、Loading、HUD 的层级 |
| 四 | 输入路由与 ActionBar | 注册 UI Action、显示按钮提示、处理 Back/Confirm/Hold |
| 五 | 设备识别与按键图标 | 配 CommonInputSettings、ControllerData、键鼠/手柄/触摸图标 |
| 六 | 按钮、Tab、List 和样式 | 做可复用按钮、选项卡、列表项、锁定态、选中态和声音 |
| 七 | 和 Enhanced Input 怎么接 | 用 InputAction、IMC Metadata、InputMapping 和 UI 输入上下文 |
| 八 | Modal、异步加载与弹窗 | 做设置页、确认框、异步图片/Widget、加载遮罩和队列弹窗 |
| 九 | HUD、暂停菜单和 Gameplay 共存 | 处理 UIOnly/GameOnly/All、鼠标捕获、游戏预览和角色输入 |
| 十 | 调试、性能和生产规范 | 用 DumpActivatableTree、showdebug ActionRouter、命名、多人和上线清单 |
Common UI 解决的不是一个点
普通 UMG 项目最容易变成“每个 Widget 自己 AddToViewport、自己 Bind Esc、自己 SetInputMode”。做到第三个菜单后,返回键顺序、焦点恢复、手柄按钮提示、弹窗遮挡、暂停菜单和游戏输入就会互相干扰。Common UI 的做法是把 UI 看成一棵“激活树”:只有当前可接收输入的 leaf-most activatable widget 最该拿输入配置和焦点。
这也是为什么源码里 UCommonUIActionRouterBase 是 ULocalPlayerSubsystem:UI 输入不是全局的,它属于本地玩家。分屏、本地双人、远程多人都不能靠一个全局单例处理。
先记住五个核心类型
| 类型 | 负责什么 | 初学者怎么理解 |
|---|---|---|
UCommonActivatableWidget | 页面生命周期、返回键、焦点、输入配置 | 一个“可打开/可关闭”的页面 |
UCommonActivatableWidgetStack | 后进先出的页面栈 | 主菜单推设置页,Back 回主菜单 |
UCommonActivatableWidgetQueue | 一个一个显示的队列 | Toast、奖励弹窗、确认结果 |
UCommonUIActionRouterBase | 把输入送给激活树 | UI 输入总调度器 |
UCommonInputSubsystem | 判断当前输入设备和图标数据 | 键鼠/手柄/触摸提示管理器 |
推荐项目骨架
项目里建议先建四个基类:WBP_RootLayout、WBP_ActivatableScreenBase、WBP_CommonButtonBase、WBP_BoundActionButton。RootLayout 里放四个层:HUD、Menu、Modal、Toast。所有页面不要直接 AddToViewport,而是通过 RootLayout 的层 Push 或 Enqueue。
生产项目里 UI 入口通常放在 PlayerController 或 LocalPlayer 相关系统:玩家进入游戏后创建 RootLayout,加到 Viewport;打开背包、设置、暂停菜单时只调用 RootLayout 的 Push。这样每个页面只关心自己的内容和返回行为。
最小配置清单
[/Script/Engine.Engine]
GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient
[/Script/CommonInput.CommonInputSettings]
bEnableEnhancedInputSupport=True
bEnableDefaultInputConfig=True
CommonGameViewportClient 很关键。源码里它会把 InputKey/InputAxis/InputTouch 先 reroute 给 Common UI 的 Action Router;如果你没配置它,源码会在非 Shipping 下提示 CommonUI 输入路由不能正常工作。
常见坑
- 把 Common UI 当成普通 UMG 控件库,只换按钮不换页面生命周期。
- 忘记配置
CommonGameViewportClient,导致 Back、ActionBar 和输入阻断不稳定。 - 所有页面都直接
AddToViewport,绕开 Stack/Queue 后返回路径无法维护。 - 页面没有实现 Desired Focus,手柄打开后看似“没输入”。
- UI Action、Gameplay Action 和改键系统各维护一套键位,最后提示图标和真实输入不一致。
源码依据
CommonUI.uplugin 在 UE5.8 里 EnabledByDefault=false,模块包含 CommonUI、CommonInput、CommonUIEditor,并依赖 EnhancedInput。CommonGameViewportClient 注释明确写着它用于把输入先路由到 UI。UCommonUIActionRouterBase 是 LocalPlayerSubsystem,负责从 ViewportClient 收集输入并转发给 activatable tree。UCommonInputSubsystem 也是 LocalPlayerSubsystem,负责当前设备、手柄类型、图标显示和输入法切换。
源码路径索引
Engine/Plugins/Runtime/CommonUI/CommonUI.upluginCommonUI/Source/CommonUI/Public/CommonActivatableWidget.hCommonUI/Source/CommonUI/Public/Widgets/CommonActivatableWidgetContainer.hCommonUI/Source/CommonUI/Public/Input/CommonUIActionRouterBase.hCommonUI/Source/CommonUI/Public/CommonGameViewportClient.hCommonInput/Public/CommonInputSubsystem.hCommonInput/Public/CommonInputSettings.hCommonUI/Public/CommonButtonBase.hCommonUI/Public/CommonActionWidget.h