UE5.8 Common UI 喂饭级专题

UE5.8 Common UI 专题(一):先跑通第一个菜单

从启用插件、配置 CommonGameViewportClient、创建 InputData 和 RootLayout 开始,手把手跑通主菜单、设置页、返回键、ActionBar 和手柄焦点。

总览

第一篇只做一件事:让你在空项目里跑通一个“主菜单 -> 设置页 -> 返回主菜单”的闭环。先别急着做十层 UI,也别先调样式。Common UI 最怕的是第一步就绕过它的入口,后面所有输入路由都会歪。

UE5.8 Common UI 专题(一):先跑通第一个菜单 配图
第一个闭环:ViewportClient 负责把输入送进 UI,RootLayout 负责页面层,Activatable Widget 负责生命周期。

第一步:启用插件和模块

编辑器里启用 Common UI Plugin。C++ 项目在 Build.cs 加:

PrivateDependencyModuleNames.AddRange(new[]
{
    "CommonUI",
    "CommonInput",
    "EnhancedInput",
    "UMG"
});

Common UI 依赖 Enhanced Input,所以项目里最好一起启用 Enhanced Input。UE5.8 源码里 CommonUI 插件默认不启用,说明它不是每个项目自动接管 UI 的功能,你必须明确把它接进项目架构。

第二步:配置 ViewportClient

DefaultEngine.ini 或 Project Settings 里设置:

[/Script/Engine.Engine]
GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient

UCommonGameViewportClient 会在 InputKeyInputAxisInputTouch 里先把输入 reroute 给 UCommonUIActionRouterBase。没有这一步,Activatable Widget 能显示,但 Back/ActionBar/输入阻断会不稳定。

第三步:做 Common Input Data

创建一个蓝图类继承 CommonUIInputData,例如 BP_CommonInputData。配置:

  • DefaultClickAction:确认/点击动作。
  • DefaultBackAction:返回动作。
  • DefaultHoldData:长按默认时间。
  • 如果开启 Enhanced Input Support,再配置 EnhancedInputClickActionEnhancedInputBackAction

然后在 Project Settings > Common Input 里把 InputData 指向这个类。源码里 UCommonInputSettings::LoadData() 会加载这个类,按钮、返回键和 ActionBar 会从这里找默认动作。

第四步:创建 RootLayout

创建 WBP_RootLayout,继承普通 UserWidget 也可以,里面放几个命名清楚的层:

控件用途
Layer_HUDOverlay/Canvas血条、小地图、任务提示
Layer_MenuCommonActivatableWidgetStack主菜单、设置、背包
Layer_ModalCommonActivatableWidgetStack确认框、阻塞弹窗
Layer_ToastCommonActivatableWidgetQueue奖励、提示、短弹窗

RootLayout 加到 Viewport 一次即可。后续页面都进 Stack/Queue,不要让各个页面自己 AddToViewport

第五步:创建 MainMenu 和 SettingsScreen

WBP_MainMenuWBP_SettingsScreen 继承 CommonActivatableWidget。MainMenu 里放“开始游戏”“设置”“退出”三个 CommonButton。SettingsScreen 里放一些选项和返回提示。

在 MainMenu 的设置按钮点击时:

Layer_Menu->AddWidget<UCommonActivatableWidget>(SettingsScreenClass);

蓝图里对应节点就是 CommonActivatableWidgetStack 的 Add Widget。源码里 Stack 的语义是:只显示并激活栈顶页面;栈顶 Deactivate 后会自动移除并重新显示/激活前一个页面。

第六步:配置返回键和焦点

WBP_SettingsScreen 上勾选:

  • Is Back Handler
  • Is Back Action Displayed In Action Bar
  • Supports Activation Focus

实现 BP_GetDesiredFocusTarget,返回页面里第一个应该聚焦的按钮。手柄项目这一步非常重要。没有 Desired Focus,页面打开后手柄导航可能看似“没反应”,其实焦点没落到可交互控件上。

第七步:放 ActionBar

创建 WBP_BoundActionButton,继承 CommonBoundActionButton,实现 CommonBoundActionButtonInterface 的默认需求,里面放一个 CommonActionWidget 和一个 CommonTextBlock,文本变量名按源码需要绑定为 Text_ActionName

再创建一个 CommonBoundActionBar 放在 RootLayout 底部或每个页面底部,ActionButtonClass 指向 WBP_BoundActionButton。当 SettingsScreen 激活并注册 Back Action 后,ActionBar 会自动显示返回提示。

常见坑

  • 忘记配置 CommonGameViewportClient,页面能显示但输入路由不完整。
  • RootLayout 每次打开菜单都 Create 一次,导致多个 Action Router 根节点和焦点互相抢。
  • 页面直接 AddToViewport,不进 Stack,Back 不知道该回到哪里。
  • 没实现 Desired Focus,手柄打开菜单后没有初始焦点。
  • 设置页关闭时手动 RemoveFromParent,而不是 DeactivateWidget,导致栈状态不一致。

源码依据

UCommonGameViewportClient 明确在输入进入游戏前调用 Action Router。UCommonActivatableWidgetStack 注释说明它是显示栈,栈顶 deactivation 后会被移除并激活前一个 widget。UCommonActivatableWidgetNativeConstruct 会在 bIsBackHandler 时注册默认 Back Action,Back 默认实现是 Deactivate 当前 Widget。

源码路径索引

  • CommonUI/Public/CommonGameViewportClient.h
  • CommonUI/Public/Widgets/CommonActivatableWidgetContainer.h
  • CommonInput/Public/CommonInputBaseTypes.h
  • CommonUI/Public/CommonActionWidget.h