【UE5 C++课程系列笔记】09——多播委托的基本使用

目录

多播委托——申明委托

一、DECLARE_MULTICAST_DELEGATE

二、DECLARE_DYNAMIC_MULTICAST_DELEGATE

多播委托——绑定委托

 一、Add

二、AddStatic

三、AddRaw

四、AddSP

五、AddUObject 

六、Remove

 七、RemoveAll

多播委托——执行

载荷数据


上一篇:【UE5 C++课程系列笔记】08——单播委托的基本使用-CSDN博客

        多播委托拥有大部分与单播委托相同的功能。它们只拥有对对象的弱引用,可以与结构体一起使用,可以四处轻松复制等等。就像常规委托一样,多播委托可以远程加载/保存和触发;但多播委托函数不能使用返回值。它们最适合用来四处轻松传递一组委托。 

        与单播委托不同的是,多播委托可以绑定多个不同对象的函数(也可以是同一个对象的多个不同函数)。当调用多播委托时,会按照绑定的顺序依次执行所有与之绑定的函数,适合于需要通知多个地方执行相关操作的场景,比如游戏中某个事件发生了,需要多个不同的系统做出响应。

多播委托——申明委托

多播委托中用于申明委托相关宏如下: 

一、DECLARE_MULTICAST_DELEGATE

        DECLARE_MULTICAST_DELEGATE 用于声明一个多播委托类型。多播委托可以绑定多个函数,当委托被触发时,所有绑定的函数都会被依次调用。

无参数的多播委托声明:

        基本语法为DECLARE_MULTICAST_DELEGATE(FDelegateName),其中FDelegateName是自定义的委托名称,用于在后续代码中定义委托实例、绑定函数等操作。

带参数的多播委托声明:

        对于带一个参数的多播委托,语法是DECLARE_MULTICAST_DELEGATE_OneParam(FDelegateName, ParamType, ParamName)。这里ParamType是参数的类型,ParamName是参数在委托中的名称,主要用于在蓝图(如果委托用于蓝图交互)或代码文档中清晰地标识参数。例如,声明一个带有一个int类型参数的多播委托:DECLARE_MULTICAST_DELEGATE_OneParam(FMyDelegateWithIntParam, int, MyIntParam);

        对于带多个参数的多播委托,如两个参数,语法是DECLARE_MULTICAST_DELEGATE_TwoParams(FDelegateName, Param1Type, Param1Name, Param2Type, Param2Name),依此类推,按照参数的数量和类型依次声明。

        假设有一个游戏中的事件系统,当玩家获得一个成就时,需要通知多个 UI 元素进行更新显示,示例代码如下:

// 1. 声明多播委托
DECLARE_MULTICAST_DELEGATE(FOnAchievementUnlocked);class APlayerController;
class AMyAchievementSystem : public AActor
{
public:// 2. 定义多播委托实例FOnAchievementUnlocked OnAchievementUnlocked;void UnlockAchievement(){// 3. 触发多播委托OnAchievementUnlocked.Broadcast();}
};class UMyAchievementUI : public UUserWidget
{
public:void BindToAchievementSystem(AMyAchievementSystem* AchievementSystem){if (AchievementSystem){// 4. 将函数绑定到多播委托AchievementSystem->OnAchievementUnlocked.AddUObject(this, &UMyAchievementUI::OnAchievementUnlockedHandler);}}void OnAchievementUnlockedHandler(){// 5. 在这里更新UI显示成就已解锁UE_LOG(LogTemp, Warning, TEXT("Achievement unlocked! Updating UI..."));}
};

二、DECLARE_DYNAMIC_MULTICAST_DELEGATE

        DECLARE_DYNAMIC_MULTICAST_DELEGATE是虚幻引擎(UE)中用于声明动态多播委托的宏。动态多播委托主要用于实现事件广播机制,允许在 C++ 代码中定义事件,并且这些事件能够方便地在蓝图(UE 的可视化脚本系统)中进行绑定和响应。这对于实现游戏中的事件系统,特别是需要在蓝图和 C++ 之间进行交互的情况非常有用。

        基本语法如下:

        (1)无参数的动态多播委托声明:

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDelegateName);

        (2)带有一个参数的动态多播委托声明:        DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDelegateName, ParamType, ParamName);

        (3)带有多个参数的动态多播委托声明(例如两个参数):DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDelegateName, Param1Type, Param1Name, Param2Type, Param2Name);

多播委托——绑定委托

绑定多播委托可使用以下7个绑定函数

 一、Add

        用于UObject实例的成员函数绑定到多播委托上。它会自动处理UObject的生命周期,当UObject被销毁时,会自动从委托中移除对应的绑定函数,防止出现悬空指针等问题。这是虚幻引擎中处理UObject相关委托绑定的常用方式,有助于确保系统的稳定性和安全性。

        在如下示例代码中,通过AddAAnotherClass实例的AnotherFunction成员函数绑定到AExampleClassMyMulticastDelegate多播委托上。

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyExampleClass.generated.h"DECLARE_MULTICAST_DELEGATE(FMyMulticastDelegate);UCLASS()
class MYGAME_API AExampleClass : public AActor
{GENERATED_BODY()
public:FMyMulticastDelegate MyMulticastDelegate;void BindFunction(){AAnotherClass* AnotherObject = NewObject<AAnotherClass>();MyMulticastDelegate.Add(AnotherObject, &AAnotherClass::AnotherFunction);}
};

二、AddStatic

        用于绑定静态函数到多播委托。静态函数是属于类本身的函数,不依赖于类的具体实例,因此在绑定到委托时,不需要考虑对象生命周期相关的问题。这使得它在处理一些通用的、不依赖于特定对象状态的逻辑时非常方便,能够为多个对象共享相同的静态函数响应委托事件。

        在如下示例代码中,通过AddStaticMyUtilityClass的静态函数StaticFunction绑定到FMyStaticDelegate多播委托上。

#include "CoreMinimal.h"
#include "MyUtilityClass.generated.h"DECLARE_MULTICAST_DELEGATE(FMyStaticDelegate);class MyUtilityClass
{
public:static void StaticFunction(){// 这里是静态函数的具体逻辑}
};void BindStaticFunction()
{FMyStaticDelegate StaticDelegate;StaticDelegate.AddStatic(&MyUtilityClass::StaticFunction);
}

三、AddRaw

        用于绑定普通的C++ 函数(非UObject相关的成员函数或静态函数)或者函数指针到多播委托。与Add()不同,它不会自动处理对象的生命周期等额外机制,开发者需要自己确保所绑定函数的有效性以及相关资源(如函数所属对象的生命周期,如果是类成员函数的话)的正确管理。这种方式提供了更大的灵活性,但也需要开发者更加谨慎地处理可能出现的问题。

        在如下示例代码中,通过AddRaw将全局函数GlobalFunction绑定到FMyRawDelegate多播委托上。

#include "CoreMinimal.h"DECLARE_MULTICAST_DELEGATE(FMyRawDelegate);void GlobalFunction()
{// 这里是全局函数的具体逻辑
}void BindRawFunction()
{FMyRawDelegate MyRawDelegate;MyRawDelegate.AddRaw(GlobalFunction);
}

四、AddSP

        主要用于绑定共享指针(TSharedPtr)指向的对象的成员函数到多播委托。在虚幻引擎中,共享指针常用于管理对象的生命周期,AddSP()结合共享指针可以确保在对象的引用计数归零时正确处理与委托的绑定关系,避免出现悬空指针等错误情况。这种方式在处理对象的共享使用和生命周期管理方面提供了一种有效的解决方案。

        在如下示例代码中,通过AddSP将共享指针SharedPtr指向的MySharedClass对象的SharedFunction成员函数绑定到FMySPDelegate多播委托上。

#include "CoreMinimal.h"
#include "MySharedClass.generated.h"DECLARE_MULTICAST_DELEGATE(FMySPDelegate);UCLASS()
class MYGAME_API MySharedClass
{GENERATED_BODY()
public:void SharedFunction(){// 这里是成员函数的具体逻辑}
};void BindSPFunction()
{TSharedPtr<MySharedClass> SharedPtr = MakeShared<MySharedClass>();FMySPDelegate MySPDelegate;MySPDelegate.AddSP(SharedPtr, &MySharedClass::SharedFunction);
}

五、AddUObject 

  AddUObject()Add()功能类似,用于UObject实例的成员函数绑定到多播委托。它是一种方便的、针对UObject的委托绑定方式,能够自动处理UObject的生命周期相关问题,保证委托在调用绑定函数时的安全性和有效性。在虚幻引擎的开发中,这种方式常用于在不同的UObject之间建立事件响应机制。

        在如下示例代码中,通过AddUObjectAAnotherClass实例的AnotherFunction成员函数绑定到AExampleClassMyMulticastDelegate多播委托上。

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyExampleClass.generated.h"DECLARE_MULTICAST_DELEGATE(FMyMulticastDelegate);UCLASS()
class MYGAME_API AExampleClass : public AActor
{GENERATED_BODY()
public:FMyMulticastDelegate MyMulticastDelegate;void BindFunction(){AAnotherClass* AnotherObject = NewObject<AAnotherClass>();MyMulticastDelegate.AddUObject(AnotherObject, &AAnotherClass::AnotherFunction);}
};

六、Remove

        用于从多播委托中移除特定的绑定函数。当不再需要某个函数对委托事件做出响应时,或者在对象生命周期结束等情况下,需要手动使用Remove()来清理委托中的绑定关系,以避免不必要的函数调用或潜在的错误。

        在如下示例代码中,先使用AddRawSomeFunction绑定到MyDelegate,然后使用Remove将其从委托中移除。

#include "CoreMinimal.h"DECLARE_MULTICAST_DELEGATE(FMyDelegate);void SomeFunction()
{// 函数逻辑
}void RemoveFunctionBinding()
{FMyDelegate MyDelegate;MyDelegate.AddRaw(SomeFunction);// 移除绑定MyDelegate.Remove(SomeFunction);
}

 七、RemoveAll

        用于移除多播委托中所有已绑定的函数。这在需要重置委托的状态,或者当持有委托的对象即将被销毁等情况下非常有用,可以确保委托处于一个干净的状态,不会在后续操作中意外调用已失效的绑定函数。

在如下代码中,RemoveAll操作会清除FMyAllDelegate多播委托中所有已绑定的函数。

#include "CoreMinimal.h"DECLARE_MULTICAST_DELEGATE(FMyAllDelegate);void RemoveAllFunctionBindings()
{FMyAllDelegate MyAllDelegate;// 假设已经绑定了一些函数,这里省略绑定过程// 移除所有绑定函数MyAllDelegate.RemoveAll();
}

多播委托——执行

        多播委托允许附加多个函数委托,然后通过调用多播委托的"Broadcast()"函数一次性同时执行多个委托函数。多播委托签名不得使用返回值。

        在多播委托上调用"Broadcast()"总是安全的,即使是在没有任何绑定时也是如此。唯一需要注意的是,如果您使用委托来初始化输出变量,通常会带来非常不利的后果。

        调用"Broadcast()"时绑定函数的执行顺序尚未定义。执行顺序可能与函数的添加顺序不相同。

        调用Broadcast()的语法如下:

MyDelegate.Broadcast();

载荷数据

        在如下代码中,当调用 MultiDelegateActor实例的函数CallSimpleMulti()时,会执行多播委托MulityDelegate,由于MulityDelegate绑定了AMultiExecuteActor实例的函数Work(),因此在CallSimpleMulti()被调用后,Work()函数也会被调用。其中,当MulityDelegate绑定委托函数的时候,将参数Health传递到委托函数。

头文件: 

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MultiDelegateActor.generated.h"DECLARE_MULTICAST_DELEGATE_OneParam(MulityDelegate, FString);UCLASS()
class STUDY_API AMultiExecuteActor : public AActor
{GENERATED_BODY()protected:virtual void BeginPlay() override;
public:AMultiExecuteActor();void Work(FString InFString, int32 InHealth);FGuid MyActorID;
};UCLASS()
class STUDY_API AMultiDelegateActor : public AActor
{GENERATED_BODY()public:	// Sets default values for this actor's propertiesAMultiDelegateActor();UFUNCTION(BlueprintCallable)void CallSimpleMulti();  //用于测试委托执行的函数protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:	// Called every framevirtual void Tick(float DeltaTime) override;MulityDelegate MulityDelegate;
};

源文件:

// Fill out your copyright notice in the Description page of Project Settings.#include "Delegate/MultiDelegateActor.h"
#include "Kismet/GameplayStatics.h"AMultiExecuteActor::AMultiExecuteActor()
{RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("LocationRoot"));MyActorID = FGuid::NewGuid();
}void AMultiExecuteActor::BeginPlay()
{AActor* ActorPtr = UGameplayStatics::GetActorOfClass(this, AMultiDelegateActor::StaticClass());if (AMultiDelegateActor* MultiDelegateActorPtr = Cast<AMultiDelegateActor>(ActorPtr)){int32 Health = 100;MultiDelegateActorPtr->MulityDelegate.AddUObject(this, &AMultiExecuteActor::Work, Health);  //绑定委托函数并进行数据载荷}
}void AMultiExecuteActor::Work(FString InFString, int32 InHealth)
{UE_LOG(LogTemp, Warning, TEXT("ID:[%s],InStr:[%s],Health:[%d]"), *MyActorID.ToString(), *InFString, InHealth);
}// Sets default values
AMultiDelegateActor::AMultiDelegateActor()
{// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = false;}void AMultiDelegateActor::CallSimpleMulti()
{MulityDelegate.Broadcast(TEXT("This is simple Multi"));
}// Called when the game starts or when spawned
void AMultiDelegateActor::BeginPlay()
{Super::BeginPlay();}// Called every frame
void AMultiDelegateActor::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}

在UEEditor中将MultiDelegateActor和MultiExecuteActor加入场景中,将MultiExecuteActor复制3份

在关卡蓝图中设置函数CallSimpleMulti()的触发方式。

 运行后可以看到当调用CallSimpleMulti()后,执行了所有MulityDelegate绑定的委托函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 写个 《系统信息采集工具》为重装系统做准备。。。

图样&#xff1a; 原码&#xff1a; # 系统信息采集工具 # 2024-12-18 # 作者&#xff1a;Hoye # 版本&#xff1a;1.0 # 功能&#xff1a;采集系统信息并保存到文件 # 使用方法&#xff1a; # 1. 运行程序 # 2. 点击“采集系统信息”按钮 # 3. 等待信息采集完成 # 4. 选择保存…

Ubuntu搭建ES8集群+加密通讯+https访问

目录 写在前面 一、前期准备 1. 创建用户和用户组 2. 修改limits.conf文件 3. 关闭操作系统swap功能 4. 调整mmap上限 二、安装ES 1.下载ES 2.配置集群间安全访问证书密钥 3.配置elasticsearch.yml 4.修改jvm.options 5.启动ES服务 6.修改密码 7.启用外部ht…

【Linux】磁盘空间莫名消失,找不到具体原因的思路

磁盘空间莫名消失&#xff0c;找不到具体原因的思路 先说下常见的几种原因&#xff1a; 1、删除的文件未释放空间 2、日志或过期文件未及时清理 3、inode导致 4、隐藏文件夹或者目录 6、磁盘碎片 最后一种单独介绍。 环境&#xff1a;情况是根分区&#xff08;/&#xf…

机动车油耗计算API集成指南

机动车油耗计算API集成指南 引言 在当今社会&#xff0c;随着机动车数量的持续增长和环保意识的不断增强&#xff0c;如何有效管理和降低车辆油耗成为了车主、车队管理者以及交通政策制定者共同关注的问题。为了帮助这些群体更好地理解和优化燃油消耗情况&#xff0c;本接口能…

Fiddle突然抓不到虚拟机的地址

Fiddle不抓虚拟机的地址了 查看是否更换了ip地址,我是因为换了网络 更换正确的ip地址

C语言基础(五)【控制语句与循环综合应用篇猜数字游戏】

文章目录 前言一、实现一个猜数字游戏二、游戏实现的步骤1. 随机数生成1.1 rand1.2 srand1.3 time1.4 设置随机数的范围 2. 菜单函数的实现 3. 游戏函数的实现 二、猜数字游戏的实现1. 不限制次数 2. 限制次数为 5 总结 前言 学习过前面有关控制语句跟循环的相关知识&#xf…

javac 编译java文件源码 怎么生成 ast语法树 步骤详解

在 javac 中&#xff0c;编译源代码并生成抽象语法树&#xff08;AST&#xff09;是一个多步骤的过程&#xff0c;涉及从源码解析到最终生成字节码。以下是详细步骤&#xff0c;描述了如何使用 javac 编译源码并生成 AST。 1. 准备源文件 javac 首先需要源文件。这些源文件是…

手游和应用出海资讯:怪物猎人AR手游累计总收入已超过2.5亿美元、SuperPlay获得迪士尼纸牌游戏发行许可

NetMarvel帮助游戏和应用广告主洞察全球市场、获取行业信息&#xff0c;以下为12月第一周资讯&#xff1a; ● 怪物猎人AR手游累计总收入已超过 2.5 亿美元 ● SuperPlay获得迪士尼纸牌游戏发行许可 ● 腾讯混元大模型上线文生视频能力 ● 网易天下事业部一拆三&#xff0c;蛋仔…

酷克数据携手江西移动入选“星河(Galaxy)”数据库潜力案例

2024 年 12 月 18 - 19 日&#xff0c;为推动打造行业交流平台&#xff0c;驱动产业创新共荣&#xff0c;大数据技术标准推进委员会以“数据重塑价值 智能链接未来”为主题&#xff0c;在北京召开为期两天的“2024 数据资产管理大会”。 在会上&#xff0c;第八届大数据“星河&…

Mysql语法之DQL查询的多行函数

Mysql的多行函数和分组 目录 Mysql的多行函数和分组多行函数概念常用的多行函数 数据分组概念语法where和having的区别 语句关键字及执行顺序语句关键字执行顺序 实际操作基本语句格式和多行操作筛选语句格式 多行函数 概念 不管函数处理多少条&#xff0c;只返回一条记录&…

Ubuntu22.04上安装esp-idf

一、安装准备# 建议使用Ubuntu 20.04 或 Ubuntu 22.04 操作系统 为了在 Ubuntu 22.04 中使用 esp-idf&#xff0c;需要安装一些依赖包 sudo apt-get install git wget flex bison gperf python3\python3-pip python3-venv cmake ninja-build ccache\libffi-dev libssl-dev dfu…

WPF 依赖属性和附加属性

除了普通的 CLR 属性&#xff0c; WPF 还有一套自己的属性系统。这个系统中的属性称为依赖属性。 1. 依赖属性 为啥叫依赖属性&#xff1f;不叫阿猫阿狗属性&#xff1f; 通常我们定义一个普通 CLR 属性&#xff0c;其实就是获取和设置一个私有字段的值。假设声明了 100 个 …

在linux系统的docker中安装GitLab

一、安装GitLab&#xff1a; 在安装了docker之后就是下载安装GitLab了&#xff0c;在linux系统中输入命令&#xff1a;docker search gitlab就可以看到很多项目&#xff0c;一般安装第一个&#xff0c;它是英文版的&#xff0c;如果英文不好可以安装twang2218/gitlab-ce-zh。 …

2024最新CF罗技鼠标宏

使用效果&#xff1a; 支持的功能 M4 7发一个点HK417 连点瞬狙炼狱加特林一个圈 下载链接 点击下载

JS CSS HTML 的代码如何快速封装

我们为什么要封装代码&#xff0c;是因为封装后的代码&#xff0c;会显得非常美观&#xff0c;减少代码的复用&#xff0c;方便我们更好的去维护代码&#xff0c;不用一个一个页面的去找去改&#xff0c;直接封装好的代码里面去改就可以了 目录 1.html代码封装 2.CSS代码封装…

使用docker拉取镜像很慢或者总是超时的问题

在拉取镜像的时候比如说mysql镜像&#xff0c;在拉取 时总是失败&#xff1a; 像这种就是网络的原因&#xff0c;因为你是连接到了外网去进行下载的&#xff0c;这个时候可以添加你的访问镜像源。也就是daemon.json文件&#xff0c;如果你没有这个文件可以输入 vim /etc/dock…

MySQL复制问题和解决

目录 环境介绍 一&#xff0c;主库执行delete&#xff0c;从库没有该数据 模拟故障 修复故障 二&#xff0c;主库执行insert&#xff0c;从库已存在该数据 模拟故障 故障恢复 三&#xff0c;主库执行update&#xff0c;从库没有该数据 模拟故障 故障恢复 四&#xf…

[RocketMQ] 发送重试机制与消费重试机制~

发送重试 RocketMQ 客户端发送消息时&#xff0c;由于网络故障等因素导致消息发送失败&#xff0c;这时客户端SDK会触发重试机制&#xff0c;尝试重新发送以达到调用成功的效果。 触发条件 客户端消息发送请求失败或超时。服务端节点处于重启或下线状态。服务端运行慢造成请…

mfc140u.dll是什么文件?如何解决mfc140u.dll丢失的相关问题

遇到“mfc140u.dll文件丢失”的错误通常影响应用程序的运行&#xff0c;这个问题主要出现在使用Microsoft Visual C环境开发的软件中。mfc140u.dll是一个重要的系统文件&#xff0c;如果它丢失或损坏&#xff0c;会导致相关程序无法启动。本文将简要介绍几种快速有效的方法来恢…

02-9.python入门基础一Python模块与包(一)

一、Python 模块的概念 &#xff08;一&#xff09;模块的基本定义 在 Python 中&#xff0c;模块&#xff08;Module&#xff09;是一种组织代码的基本单元&#xff0c;简单来说&#xff0c;一个以 .py 结尾的 Python 文件就是一个模块。例如&#xff0c;我们创建一个名为 ex…