UE5:C++ 实现 游戏逻辑 ↔ UI 双向联动


观众老爷们大家好 我是邪修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++ 暂停游戏

相关推荐
汉克老师11 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
智者知已应修善业14 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
云泽80816 小时前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
AI进化营-智能译站17 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
Morwit17 小时前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
qeen8717 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码17 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler0117 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy11317 小时前
Linux进程与线程编程详解
linux·c++