虚幻引擎_UI搭建流程

基本步骤:

1. 新建继承自UserWidget类型的 C++ 类,命名为HUDWidget。

2. 基于上述HUDWidget类,创建一个对应的蓝图子类, 命名为WBP_HUD

3. 完善UI内容

4. 在目标C++类中调用:有三种常见的方法:

在PlayerController中:

在角色类中:

在游戏模式中:

cpp 复制代码
//.cpp
// 1. 获取游戏世界里的第一个玩家控制器 (索引 0)
// 如果你在玩家控制器里写代码, 就无需获取控制器
APlayerController* TargetPC = UGameplayStatics::GetPlayerController(this, 0);

if (TargetPC && HUDWidgetClass)
{
    // 如果你在玩家控制器里写代码, 就无需用TaegetPC, 直接用this就可以
    HUDWidget = CreateWidget<UHUDWidget>(TargetPC, HUDWidgetClass);

	if (HUDWidget)
	{
		HUDWidget->AddToViewport();
	}
}
cpp 复制代码
//.h
#include "HUDWidget.h"

UPROPERTY(EditAnywhere)
TSubclassOf<UHUDWidget> HUDWidgetClass;

UPROPERTY(VisibleAnywhere)
UHUDWidget* HUDWidget;

1. 在 PlayerController 中调用 (👑 行业标准/最佳实践)

这是最推荐的方案,特别是对于复杂的项目。

逻辑含义 :PlayerController 代表"玩家的大脑/灵魂"。无论你的坦克是炸了、换了一辆新坦克、还是玩家正在观看死亡回放,控制器的生命周期是一直存在的。

适用场景:

  • 常驻 UI:血条、弹药、小地图、暂停菜单。

  • 跨载具游戏:比如像《GTA》或《战地》,玩家从坦克出来走进飞机,UI 应该由控制器负责切换,而不是由坦克负责。

代码逻辑:

cpp 复制代码
// PlayerController.cpp
void AMyPlayerController::BeginPlay() {
    if (IsLocalPlayerController() && HUDClass) { // 只给本地玩家创建
        HUDWidget = CreateWidget(this, HUDClass);
        HUDWidget->AddToViewport();
    }
}

优缺点:

  • ✅ 最稳定:坦克炸了,UI 不会莫名其妙消失(除非你手动移除)。

  • ✅ 分屏完美支持:引擎会自动为玩家 1 生成控制器 1,为玩家 2 生成控制器 2。每个控制器只管自己的 UI,互不干扰。

  • ❌ 稍微麻烦:你需要新建一个 C++ Controller 类并在 GameMode 里配置它。


2. 在角色/Pawn类 (Tank) 中调用 (⚡️ 简单直接/适合本项目)

这是最适合你当前项目的方案(如果你不想创建 Controller 类)。

逻辑含义:Tank 代表"躯体"。"因为我有了这具身体,所以我才需要看这具身体的血量"。

适用场景:

  • 强绑定 UI:这个 UI 只是为了显示这辆坦克的特定信息(比如坦克的过热条)。

  • 简单项目:没有复杂的重生、换车逻辑。

代码逻辑:

cpp 复制代码
// Tank.cpp
void ATank::BeginPlay() {
    if (IsLocallyControlled() && HUDClass) { // 关键:只在被玩家控制时显示
        APlayerController* PC = Cast<APlayerController>(GetController());
        if (PC) {
            HUDWidget = CreateWidget(PC, HUDClass);
            HUDWidget->AddToViewport();
        }
    }
}

优缺点:

  • ✅ 最直观:血量变量就在 Tank 里,UI 也在 Tank 里创建,传参非常方便。

  • ✅ 自动化分屏:生成两辆坦克,自然就生成了两份 UI。

  • ❌ 生命周期风险:如果坦克炸了(调用 Destroy),挂在坦克身上的 UI 指针也就丢了(虽然 UI 可能还在屏幕上,但你无法再更新它,或者导致内存泄漏)。通常需要在 EndPlay 或死亡时手动 RemoveFromParent。


3. 在 GameMode 中调用 (❌ 反面教材/通常不推荐)

除非是特殊情况,否则强烈不建议在这里创建玩家的 HUD(血条等)。

逻辑含义:GameMode 代表"裁判/规则"。裁判不应该管某个具体球员穿什么鞋子(UI)。

为什么不推荐:

  1. 服务器端运行:GameMode 只存在于服务器。在网络联机游戏中,客户端根本没有 GameMode,这会导致 UI 根本创建不出来。

  2. 所有权混乱:GameMode 不属于任何一个玩家。

  3. 分屏噩梦:你必须写 for 循环遍历所有玩家来给他们发 UI,如果玩家中途加入或退出,管理起来非常痛苦。

唯一适用的场景:

  • 全局广播:比如"服务器将在 5 分钟后关闭"、"全服公告"。

  • 单人游戏的特殊流程:比如 Level 加载画面(但通常也不用 GameMode 做)。

代码逻辑(为了演示为什么麻烦):

cpp 复制代码
// GameMode.cpp
void AMyGameMode::BeginPlay() {
    // 你必须手动获取每一个控制器,非常僵硬
    APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
    CreateWidget(PC, ...)->AddToViewport();
}

总结与选择建议

以 本地双人分屏坦克对战 项目为例:

|------------|--------------------|------------------|--------------|
| 维度 | PlayerController | Character (Tank) | GameMode |
| 推荐指数 | ⭐⭐⭐⭐⭐ (最标准) | ⭐⭐⭐⭐ (最快捷) | ⭐ (别用) |
| UI 归属感 | UI 属于玩家 (大脑) | UI 属于载具 (身体) | UI 属于上帝 (规则) |
| 坦克死亡后 | UI 依然存活,可显示"复活倒计时" | UI 通常随坦克一起销毁 | 与坦克无关,但这很不合理 |
| 分屏适配 | 完美自动适配 | 完美自动适配 | 需要手动写循环管理 |

5. 在蓝图中挂载

相关推荐
把我格子衫拿来6 小时前
VTK 9.5 与 Qt 6 联合开发:从嵌入三维窗口到可维护的桌面架构
c++·python·qt·vtk·三维可视化
无忧.芙桃7 小时前
C++语言原理与实践(十六):多态机制讲解
开发语言·c++·多态
wuminyu8 小时前
JMM学习总结:深入理解happens-before关系
java·linux·c语言·jvm·c++
xxwl5858 小时前
区域赛分类题解
c++·笔记·学习·算法
青少儿编程课堂9 小时前
蓝桥杯+全国青少年信息素养大赛+电子学会PythonC/C++考级:最长公共子序列LCS解析
c++·python·算法·bfs·信息学竞赛
代钦塔拉10 小时前
【C++/Qt 进阶】设计模式系列(2):工厂模式——从游戏角色到披萨店
c++·算法·设计模式
把我格子衫拿来12 小时前
VTK 与 Qt 的 CMake 工程怎么组织?模块、工具链与二进制兼容排错
c++·qt·vtk·cmake·工程实践
灯澜忆梦13 小时前
【面向对象编程c++】| 指针与自定义数据类型
开发语言·c++·算法
xxwl58513 小时前
区域赛算法模版第八章---贪心(Greedy)
c++·笔记·学习·算法
雾沉川13 小时前
Visual C++运行库合集 v105.0 安装教程
开发语言·c++·dll