
观众老爷们大家好 我是邪修KING 欢迎来到我的TA->UE游戏引擎博客---入门篇! C++!高门槛!精选学习! 根据前几篇文章的学习,我们现在已经会蓝图 UI 了,这一篇我们开始直接最标准、最工程化、游戏厂商最常用 的 C++ + UMG 联动方案,一步一步跟着做就能跑通 。
我们用好现有的项目(玩家立方体、血量、移动速度、UI)直接实现,不用新建项目。
核心一句话
游戏逻辑(C++ Actor)发事件 → UI(C++ UMG)监听事件 → 自动更新界面 这就是 UE 最标准的 解耦架构。
一、整体结构(你必须先看懂)
我们要创建 2 个 C++ 类:
1.PlayerActor.cpp (游戏逻辑:血量、移动、受伤)
2 .PlayerHUD.cpp (UI:显示血量、速度、接收事件更新)
通信方式:
· C++ 多播委托(动态多播) = 蓝图的 "事件分发器"
· UI 绑定委托 → 玩家逻辑调用委托 → UI 自动刷新
二、完整可复制代码(直接用)
1. 玩家 C++ 类(负责游戏逻辑)
MyPlayerActor.h
cpp
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyPlayerActor.generated.h"
UCLASS()
class MYPROJECT_API AMyPlayerActor : public AActor
{
GENERATED_BODY()
public:
AMyPlayerActor();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
// 血量
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float MaxHealth = 100.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")
float CurrentHealth;
// 移动速度
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MoveSpeed = 500.0f;
// ==========================================
// 【关键】委托:血量变化时广播事件
// ==========================================
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);
UPROPERTY(BlueprintAssignable, Category = "Events")
FOnHealthChanged OnHealthChanged;
// 受伤函数
UFUNCTION(BlueprintCallable, Category = "Health")
void TakeDamage(float Damage);
};
二、完整代码(直接用)
1. 玩家 C++ 类(负责游戏逻辑)
MyPlayerActor.h
cpp
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyPlayerActor.generated.h"
UCLASS()
class MYPROJECT_API AMyPlayerActor : public AActor
{
GENERATED_BODY()
public:
AMyPlayerActor();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
// 血量
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
float MaxHealth = 100.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")
float CurrentHealth;
// 移动速度
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MoveSpeed = 500.0f;
// 【关键】委托:血量变化时广播事件
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);
UPROPERTY(BlueprintAssignable, Category = "Events")
FOnHealthChanged OnHealthChanged;
// 受伤函数
UFUNCTION(BlueprintCallable, Category = "Health")
void TakeDamage(float Damage);
};
MyPlayerActor.cpp
cpp
#include "MyPlayerActor.h"
AMyPlayerActor::AMyPlayerActor()
{
PrimaryActorTick.bCanEverTick = true;
CurrentHealth = MaxHealth;
}
void AMyPlayerActor::BeginPlay()
{
Super::BeginPlay();
}
void AMyPlayerActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AMyPlayerActor::TakeDamage(float Damage)
{
CurrentHealth = FMath::Clamp(CurrentHealth - Damage, 0.0f, MaxHealth);
// 【关键】广播事件 → UI 会收到
OnHealthChanged.Broadcast(CurrentHealth);
}
2. UI C++ 类(负责显示、接收事件)
MyPlayerHUD.h
cpp
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MyPlayerHUD.generated.h"
class AMyPlayerActor;
class UProgressBar;
class UTextBlock;
UCLASS()
class MYPROJECT_API UMyPlayerHUD : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativeOnInitialized() override;
public:
// 绑定控件
UPROPERTY(meta = (BindWidget))
UProgressBar* HealthBar;
UPROPERTY(meta = (BindWidget))
UTextBlock* SpeedText;
// 玩家引用
UPROPERTY(EditAnywhere, BlueprintReadWrite)
AMyPlayerActor* PlayerRef;
// 更新血量条
UFUNCTION()
void UpdateHealth(float NewHealth);
// 更新速度(每帧)
void UpdateSpeed();
};
MyPlayerHUD.cpp
cpp
#include "MyPlayerHUD.h"
#include "MyPlayerActor.h"
#include "Components/ProgressBar.h"
#include "Components/TextBlock.h"
void UMyPlayerHUD::NativeOnInitialized()
{
Super::NativeOnInitialized();
if (PlayerRef)
{
// 【关键】UI 绑定玩家的事件
PlayerRef->OnHealthChanged.AddDynamic(this, &UMyPlayerHUD::UpdateHealth);
}
}
void UMyPlayerHUD::UpdateHealth(float NewHealth)
{
if (HealthBar && PlayerRef)
{
HealthBar->SetPercent(NewHealth / PlayerRef->MaxHealth);
}
}
void UMyPlayerHUD::UpdateSpeed()
{
if (SpeedText && PlayerRef)
{
SpeedText->SetText(FText::FromString(
FString::Printf(TEXT("Move Speed: %.1f"), PlayerRef->MoveSpeed)
));
}
}
三、引擎内操作(5 步完成)
1. 创建 C++ 类
新建 Actor 类 → 命名 MyPlayerActor
新建 UserWidget 类 → 命名 MyPlayerHUD
把上面代码粘贴进去。
2. 创建 UI 控件蓝图(必须继承 C++ 类)
1.右键 → 用户界面 → 控件蓝图
2.父类选择 MyPlayerHUD
3.打开控件蓝图,你会看到:
==HealthBar
==SpeedText
已经自动存在!
直接拖进视口就行,名字必须一样:
==进度条 → 命名 HealthBar
==文本 → 命名 SpeedText
3. 玩家蓝图继承 C++ 类
1.打开你的 BP_CubeTest
2.右上角 类设置
3.父类选择 MyPlayerActor
你的玩家现在变成 C++ 逻辑 + 蓝图编辑
4. 游戏开始时显示 UI
打开玩家 C++ 或蓝图的 BeginPlay:
cpp
// C++ 显示 UI
if (UWorld* World = GetWorld())
{
UMyPlayerHUD* HUD = CreateWidget<UMyPlayerHUD>(World, UMyPlayerHUD::StaticClass());
if (HUD)
{
HUD->PlayerRef = this;
HUD->AddToViewport();
}
}
5. 测试:碰撞扣血
在障碍物碰撞时调用:
cpp
Player->TakeDamage(20.0f);
四、核心原理(你必须理解)
1. 游戏逻辑 → UI 用 委托(动态多播)
cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);
OnHealthChanged.Broadcast(CurrentHealth);
= 蓝图的 事件分发器
2. UI 监听事件
cpp
PlayerRef->OnHealthChanged.AddDynamic(this, &UMyPlayerHUD::UpdateHealth);
= 蓝图的 绑定事件
3. 完全解耦
1.玩家不知道 UI 存在
2.UI 不知道玩家内部逻辑
这就是 UE 工程化标准架构
五、总结
1.C++ 扣血 → UI 血量条自动刷新
2.C++ 改速度 → UI 文字实时更新
3.C++ 游戏结束 → UI 显示结束面板
4.UI 按钮点击 → 调用 C++ 暂停游戏
