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 - 跟踪的目标 Actor
  • WorldOffset - 世界空间偏移(如血条显示在头顶)
  • 每帧将 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。

生命周期

  1. 创建时(NativeConstruct)绑定 ActionComponent 的 OnActionStopped 事件
  2. 异步加载效果图标纹理
  3. 加载完成后设置到 Material Instance Dynamic 的 “Icon” 参数
  4. 当对应的 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;