Ue c++、蓝图开发指南 Part 05:umg 基础ui界面
目录
[TOC]
一、角色健康栏–蓝图版
-
修改
STUHealthComponent:添加函数GetHealthPercentUCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class SHOOTTHEMUP_API USTUHealthComponent : public UActorComponent{ ... public: // 获取角色当前生命值 float GetHealth() const { return Health; } // 获取角色当前生命值百分比 UFUNCTION(BlueprintCallable, Category = "Health") float GetHealthPercent() const { return Health / MaxHealth; } ... }; -
创建文件夹
UI,然后在该目录下创建用户界面/控件蓝图,重命名为WBP_PlayerHUD -
基于
STUGameHUD,创建蓝图类BP_STUGameHUD- 路径:
UI
- 路径:
-
修改
BP_STUGameHUD:
-
将HUD类设置为
BP_STUGameHUD,在游戏中可以通过Shift+F1解放鼠标 -
修改
WBP_PlayerHUD- 添加
进度条控件,将填充颜色设为绿色 - 对
进度/百分比属性创建绑定,函数重命名为Get_HealthPercent

- 添加
-
修改
BP_BaseCharacter/HealthComponent中,有关自动回复的参数
二、角色健康栏–C++版
-
创建C++类
STUPlayerHUDWidget,继承于UserWidget- 目录:
ShootThemUp/Source/ShootThemUp/Public/UI
- 目录:
-
修改
STUPlayerHUDWidget#pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "STUPlayerHUDWidget.generated.h" UCLASS() class SHOOTTHEMUP_API USTUPlayerHUDWidget : public UUserWidget { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "UI") float GetHealthPercent() const; };```c++ #include “UI/STUPlayerHUDWidget.h” #include “Components/STUHealthComponent.h”
float USTUPlayerHUDWidget::GetHealthPercent() const { const auto Player = GetOwningPlayerPawn(); if (!Player) return 0.0f;
const auto Component = Player->GetComponentByClass(USTUHealthComponent::StaticClass()); const auto HealthComponent = Cast<USTUHealthComponent>(Component); if (!HealthComponent) return 0.0f; return HealthComponent->GetHealthPercent(); } -
修改
STUGameHUD#pragma once #include "CoreMinimal.h" #include "GameFramework/HUD.h" #include "STUGameHUD.generated.h" UCLASS() class SHOOTTHEMUP_API ASTUGameHUD : public AHUD { GENERATED_BODY() protected: UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "UI") TSubclassOf<UUserWidget> PlayerHUDWidgetClass; virtual void BeginPlay() override; };```c++ #include “Blueprint/UserWidget.h”
void ASTUGameHUD::BeginPlay() { Super::BeginPlay(); auto PlayerHUDWidget = CreateWidget
(GetWorld(), PlayerHUDWidgetClass); if (PlayerHUDWidget) { PlayerHUDWidget->AddToViewport(); } } -
修改
WBP_PlayerHUD:- 修改父类:在
文件/重设蓝图父项中,修改父类为STUPlayerHUDWidget - 修改
图表/Get_HealthPercent函数:将计算过程隐藏与C++类中

- 修改父类:在
-
修改
BP_STUGameHUD:- 将事件图表中的蓝图删除,因为我们已经在C++中实现了
- 将
类默认值/PlayerHUDWidgetClass设置为WBP_PlayerHUD- 可以通过修改这个属性,选择创建哪一种UI界面
三、每种武器的瞄准UI
-
将
UI/Images迁移到本项目中 -
修改
WBP_PlayerHUD- 添加
图像控件,选择RifleCrossHair,然后勾选大小到内容 - 将锚点修改为
中央,位置X(Y)均设置为0,对齐设置为(0.5,0.5)

- 添加
-
修改
STUCoreType:创建新类型FWeaponUIDataUSTRUCT(BlueprintType) struct FWeaponUIData { GENERATED_USTRUCT_BODY() // 武器的图标 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "UI") UTexture2D* MainIcon; // 武器的瞄准线图标 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "UI") UTexture2D* CrossHairIcon; }; -
修改
STUBaseWeapon:添加武器的显示UI数据```c++ UCLASS() class SHOOTTHEMUP_API ASTUBaseWeapon : public AActor { …
public: FWeaponUIData GetUIData() const { return UIData; }
protected: // 武器的显示UI UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = “UI”) FWeaponUIData UIData; };
-
修改
STUWeaponComponent:添加UIData的getter函数UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class SHOOTTHEMUP_API USTUWeaponComponent : public UActorComponent { GENERATED_BODY() public: // 获取武器UI数据 bool GetWeaponUIData(FWeaponUIData& UIData) const; };bool USTUWeaponComponent::GetWeaponUIData(FWeaponUIData& UIData) const { if (!CurrentWeapon) return false; UIData = CurrentWeapon->GetUIData(); return true; } -
修改
STUPlayerHUDWidget:添加UIData的getter函数... #include "STUCoreTypes.h" UCLASS() class SHOOTTHEMUP_API USTUPlayerHUDWidget : public UUserWidget { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "UI") float GetHealthPercent() const; UFUNCTION(BlueprintCallable, Category = "UI") bool GetWeaponUIData(FWeaponUIData& UIData) const; };bool USTUPlayerHUDWidget::GetWeaponUIData(FWeaponUIData& UIData) const { const auto Player = GetOwningPlayerPawn(); if (!Player) return false; const auto Component = Player->GetComponentByClass(USTUWeaponComponent::StaticClass()); const auto WeaponComponent = Cast<USTUWeaponComponent>(Component); if (!WeaponComponent) return false; return WeaponComponent->GetWeaponUIData(UIData); } -
修改
STUGameHUD/DrawHUD```c++ void ASTUGameHUD::DrawHUD() { Super::DrawHUD(); // DrawCrossHair(); }
-
修改
WBP_PlayerHUD- 对
图像框/外观/笔刷属性进行绑定,函数重命名为Get_CrossHairImage

- 对
-
为每种武器设置
UIDataBP_STURifleWeapon:RifleMainIcon、RifleCrossHairBP_STULauncherWeapon:LauncherMainIcon、LauncherCrossHair
-
修改
SkySphere:清除Direction Light Actor,Sun Height设置为-1
四、实战作业:武器弹药库UI
-
修改
STUBaseWeapon:添加AmmoData的getter```c++ UCLASS() class SHOOTTHEMUP_API ASTUBaseWeapon : public AActor { …
public: FAmmoData GetAmmoData() const { return CurrentAmmo; } };
-
修改
STUWeaponComponent:添加CurrentAmmoData的getter函数UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class SHOOTTHEMUP_API USTUWeaponComponent : public UActorComponent { GENERATED_BODY() public: // 获取武器弹药库数据 bool GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const; };bool USTUWeaponComponent::GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const { if (!CurrentWeapon) return false; AmmoData = CurrentWeapon->GetAmmoData(); return true; } -
修改
STUPlayerHUDWidget:添加UIData的getter函数,将获取武器组件的功能抽象出来class USTUWeaponComponent; UCLASS() class SHOOTTHEMUP_API USTUPlayerHUDWidget : public UUserWidget { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "UI") float GetHealthPercent() const; UFUNCTION(BlueprintCallable, Category = "UI") bool GetCurrentWeaponUIData(FWeaponUIData& UIData) const; UFUNCTION(BlueprintCallable, Category = "UI") bool GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const; private: USTUWeaponComponent* GetWeaponComponent() const; };bool USTUPlayerHUDWidget::GetCurrentWeaponUIData(FWeaponUIData& UIData) const { const auto WeaponComponent = GetWeaponComponent(); if (!WeaponComponent) return false; return WeaponComponent->GetCurrentWeaponUIData(UIData); } bool USTUPlayerHUDWidget::GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const { const auto WeaponComponent = GetWeaponComponent(); if (!WeaponComponent) return false; return WeaponComponent->GetCurrentWeaponAmmoData(AmmoData); } USTUWeaponComponent* USTUPlayerHUDWidget::GetWeaponComponent() const { const auto Player = GetOwningPlayerPawn(); if (!Player) return nullptr; const auto Component = Player->GetComponentByClass(USTUWeaponComponent::StaticClass()); const auto WeaponComponent = Cast<USTUWeaponComponent>(Component); return WeaponComponent; } -
修改
WBP_PlayerHUD-
修改
Get_CrossHairImage:

-
添加控件:
-
水平框:勾选大小到内容,锚点为右下角,位置为(-50,-50),对齐为(1,1) -
文本:默认为0 / 0,绑定为函数,重命名为Get_AmmoText
-
间隔区:外观/尺寸为(30,1) -
图像:预览图为RifleMainIcon,绑定为函数,重命名为Get_WeaponIcon
-
-
五、观察者模式的UI
-
修改
STUPlayerHUDWidget:添加判断角色是否存活 & 是否处于观察者模式UCLASS() class SHOOTTHEMUP_API USTUPlayerHUDWidget : public UUserWidget { ... public: // 玩家是否存活 UFUNCTION(BlueprintCallable, Category = "UI") bool IsPlayerAlive() const; // 玩家是否处于观察者模式 UFUNCTION(BlueprintCallable, Category = "UI") bool IsPlayerSpectating() const; private: USTUHealthComponent* GetHealthComponent() const; };```c++ // 玩家是否存活 bool USTUPlayerHUDWidget::IsPlayerAlive() const { const auto HealthComponent = GetHealthComponent(); return HealthComponent && !HealthComponent->IsDead(); }
// 玩家是否处于观察者模式 bool USTUPlayerHUDWidget::IsPlayerSpectating() const { const auto Controller = GetOwningPlayer(); return Controller && Controller->GetStateName() == NAME_Spectating; }
-
修改
WBP_PlayerHUD:-
ProgressBar_0:绑定可视性属性,函数重命名为Is_Player_Alive
-
Image_0:绑定为Is_Player_Alive -
水平框:绑定为Is_Player_Alive
-
-
创建用户界面/控件蓝图
WBP_SpectatorHUD:- 添加控件
循环动态流览图显示:图像块数量为14,周期为3,颜色为红色 - 添加控件
文本框:默认文本为您已死亡 - 添加控件
覆层,并将上述两个控件作为覆层的子控件:位置为(0,0),尺寸为(200,200)
- 添加控件
-
修改
WBP_PlayerHUD:-
添加控件
WBP_SpectatorHUD:锚点为居中,位置为(0,0),对齐为(0.5,0.5)- 绑定
可视性属性,函数重命名为Is_Player_Spectating

-
-
修改
WBP_SpectatorHUD:-
选中文本框,添加动画
TextBlinking-
添加轨道/文本
DeadTextBlock -
添加轨道
颜色和不透明度,在该轨道上添加关键帧
-
-
修改事件图表:在初始化时开始播放动画

-
六、重构,组装游戏
-
创建C++类
STUUtils- 目录:
ShootThemUp/Source/ShootThemUp/Public
- 目录:
-
修改
STUUtils:将两个component的getter合并为一个模板函数#pragma once class STUUtils { public: template<typename T> static T* GetSTUPlayerComponent(APawn* PlayerPawn) { if (!PlayerPawn) return nullptr; const auto Component = PlayerPawn->GetComponentByClass(T::StaticClass()); return Cast<T>(Component); } }; -
修改
STUPlayerHUD:使用STUUtils获取两个component#pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "STUCoreTypes.h" #include "STUPlayerHUDWidget.generated.h" UCLASS() class SHOOTTHEMUP_API USTUPlayerHUDWidget : public UUserWidget { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "UI") float GetHealthPercent() const; UFUNCTION(BlueprintCallable, Category = "UI") bool GetCurrentWeaponUIData(FWeaponUIData& UIData) const; UFUNCTION(BlueprintCallable, Category = "UI") bool GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const; // 玩家是否存活 UFUNCTION(BlueprintCallable, Category = "UI") bool IsPlayerAlive() const; // 玩家是否处于观察者模式 UFUNCTION(BlueprintCallable, Category = "UI") bool IsPlayerSpectating() const; };```c++ #include “UI/STUPlayerHUDWidget.h” #include “Components/STUHealthComponent.h” #include “Components/STUWeaponComponent.h” #include “STUUtils.h”
float USTUPlayerHUDWidget::GetHealthPercent() const { const auto HealthComponent = STUUtils::GetSTUPlayerComponent
(GetOwningPlayerPawn()); if (!HealthComponent) return 0.0f; return HealthComponent->GetHealthPercent(); }bool USTUPlayerHUDWidget::GetCurrentWeaponUIData(FWeaponUIData& UIData) const { const auto WeaponComponent = STUUtils::GetSTUPlayerComponent
(GetOwningPlayerPawn()); if (!WeaponComponent) return false; return WeaponComponent->GetCurrentWeaponUIData(UIData); }bool USTUPlayerHUDWidget::GetCurrentWeaponAmmoData(FAmmoData& AmmoData) const { const auto WeaponComponent = STUUtils::GetSTUPlayerComponent
(GetOwningPlayerPawn()); if (!WeaponComponent) return false; return WeaponComponent->GetCurrentWeaponAmmoData(AmmoData); }// 玩家是否存活 bool USTUPlayerHUDWidget::IsPlayerAlive() const { const auto HealthComponent = STUUtils::GetSTUPlayerComponent
(GetOwningPlayerPawn()); return HealthComponent && !HealthComponent->IsDead(); } // 玩家是否处于观察者模式 bool USTUPlayerHUDWidget::IsPlayerSpectating() const { const auto Controller = GetOwningPlayer(); return Controller && Controller->GetStateName() == NAME_Spectating; }
-
修改
STUBaseWeapon:删除每次射击后调用LogAmmo()```c++ void ASTUBaseWeapon::DecreaseAmmo() { CurrentAmmo.Bullets–;
if (IsClipEmpty() && !IsAmmoEmpty()) ChangeClip(); } -
修改
WBP_PlayerHUD的命名: