UI 系统
概述
UI 系统提供 HUD、世界空间 Widget 和效果图标 Widget。核心设计是将世界空间 UI 统一添加到主 HUD 的 CanvasPanel 中,通过手动投影世界坐标到屏幕坐标实现位置跟踪。
核心类
ARogueHUD
文件: Source/ActionRoguelike/UI/RogueHUD.h/.cpp
HUD 类,管理暂停菜单。
暂停菜单:
TogglePauseMenu()- 切换暂停菜单显示- 显示时:创建 Widget、显示鼠标、切换到 UI 输入模式
- 隐藏时:移除 Widget、隐藏鼠标、恢复游戏输入
- 仅在单机模式(
NM_Standalone)下实际暂停游戏 - Widget 添加到 Viewport 的 ZOrder=100 确保在最顶层
URogueWorldUserWidget
文件: Source/ActionRoguelike/UI/RogueWorldUserWidget.h/.cpp
世界空间 UI Widget 基类,用于显示血条、交互提示、“被发现"提示等。
核心机制:
AttachedActor- 跟踪的目标 ActorWorldOffset- 世界空间偏移(如血条显示在头顶)- 每帧将 Actor 世界坐标投影到屏幕坐标
- 通过设置
RenderTranslation更新位置 - 目标失效时自动移除
屏幕外优化:
if (bWasOnScreen != bIsOnScreen)
{
ParentOverlay->SetVisibility(
bIsOnScreen ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed
);
}
仅在可见性变化时更新,避免不必要的 Slate 失效。
统一面板管理:
static void AddToRootCanvasPanel(UUserWidget* InNewWidget);
所有世界空间 Widget 都添加到主 HUD 的 CanvasPanel 中,而非直接添加到 Viewport。好处是可以统一管理层级关系。
NativeConstruct: 自动配置 CanvasPanelSlot 的对齐方式(居中底部)和自动尺寸。
URogueEffectSlotWidget
文件: Source/ActionRoguelike/UI/RogueEffectSlotWidget.h/.cpp
效果/Buff 图标 Widget,显示当前激活的 ActionEffect。
生命周期:
- 创建时(NativeConstruct)绑定 ActionComponent 的
OnActionStopped事件 - 异步加载效果图标纹理
- 加载完成后设置到 Material Instance Dynamic 的 “Icon” 参数
- 当对应的 Effect 停止时自动移除自身
异步加载:
FSoftObjectPath IconPath = EffectInst->GetIcon().ToSoftObjectPath();
LoadAssetAsync(IconPath.GetAssetPath(), Delegate);
UI 架构图
ARogueHUD (HUD)
└── 主 HUD Widget (蓝图创建)
└── UCanvasPanel (根 Widget)
├── URogueWorldUserWidget (血条)
│ └── 跟踪 AI 角色位置
├── URogueWorldUserWidget (交互提示)
│ └── 跟踪可交互物体位置
├── URogueWorldUserWidget ("被发现"提示)
│ └── 跟踪发现玩家的 AI 位置
└── URogueEffectSlotWidget (Buff 图标)
└── 跟踪当前激活的 ActionEffect
暂停菜单 (独立于主 HUD)
└── 直接添加到 Viewport (ZOrder=100)
使用方式
创建世界空间 Widget
// 创建血条
URogueWorldUserWidget* HealthBar = CreateWidget<URogueWorldUserWidget>(GetWorld(), HealthBarWidgetClass);
HealthBar->AttachedActor = this;
URogueWorldUserWidget::AddToRootCanvasPanel(HealthBar);
创建效果图标(蓝图中)
EffectSlotWidget 使用 ExposeOnSpawn 属性,创建时传入 EffectInst:
UPROPERTY(BlueprintReadOnly, meta = (ExposeOnSpawn=true))
TObjectPtr<URogueActionEffect> EffectInst;