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++ 暂停游戏

相关推荐
资源分享助手10 小时前
杀戮尖塔2下载、Slay the Spire 2中文版、卡牌肉鸽游戏、杀戮尖塔2联机、杀戮尖塔2攻略
游戏
森G11 小时前
77、线程池原理和实现------服务器源码解析----云视频服务项目
服务器·c++·qt
.千余11 小时前
【C++】模板进阶全解:非类型参数|全特化|偏特化|分离编译完全指南
开发语言·c++·笔记·学习·其他
代码改善世界11 小时前
【C++进阶】C++11:列表初始化、右值引用与移动语义、完美转发全解析
java·开发语言·c++
牛油果子哥q12 小时前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
小冷爱读书12 小时前
allocator
开发语言·c++
森G12 小时前
71、打包发布---------打包发布
c++·qt
小冷爱读书12 小时前
C++ 单例四种实现完整演进逻辑
开发语言·c++·c++学习
sdm07042712 小时前
多路转接-select
网络·c++·select·多路转接
beethobe12 小时前
PythonQt 学习之旅(一):从零构建 C++ 与 Python 的桥梁
c++·python·学习