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

news2024/12/17 18:06:55

目录

多播委托——申明委托

一、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();

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

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

相关文章

车牌识别OCR授权:助力国产化升级,全面提升道路监控效率

政策背景&#xff1a;国产化升级&#xff0c;推动道路监控产业转型 随着国家对信息安全的重视&#xff0c;国内各大公安、政企机构已进入全面升级国产化平台的实施阶段。根据最新的政策要求&#xff0c;公安和政府部门必须在未来三年内完成平台的国产化替换工作。这一举措不仅…

无人机推流直播平台EasyDSS视频技术如何助力冬季森林防火

冬季天干物燥&#xff0c;大风天气频繁&#xff0c;是森林火灾的高发期。相比传统的人力巡查&#xff0c;无人机具有更高的灵敏度和准确性&#xff0c;尤其在夜间或浓雾天气中&#xff0c;依然能有效地监测潜在火源。 无人机可以提供高空视角和实时图像传输&#xff0c;帮助巡…

linux下查看nginx的安装路径

一般会安装在默认位置下&#xff1a;/usr/local/openresty/nginx 或/usr/local/nginx 查看nginx运行进程&#xff0c;mast process 后面一般是nginx 的安装目录 ps -aux|grep nginx执行ls -l /proc/进程号/exe 会打印出安装/运行位置 ps -aux|grep nginx ls -l /proc/进程号/ex…

Python随机抽取Excel数据并在处理后整合为一个文件

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件&#xff0c;随机从其中选取一部分数据&#xff0c;并将全部文件中随机获取的数据合并为一个新的Excel表格文件的方法。 首先&#xff0c;我们来明确一下本文的具体需求。…

网络基础 - TCP/IP 五层模型

文章目录 一、OSI 参考模型中各个分层的作用1、应用层2、表示层3、会话层4、传输层5、网络层6、数据链路层7、物理层 二、OSI 参考模型通信处理示例三、TCP/IP1、定义2、规范 - RFC(Request For Comment) 一、OSI 参考模型中各个分层的作用 1、应用层 2、表示层 负责设备固有数…

探索Web3:从去中心化应用到全球数字化未来

Web3 是互联网发展的下一步&#xff0c;它通过去中心化的理念重新定义了数字世界。与传统的Web2相比&#xff0c;Web3将数据主权交还给用户&#xff0c;让每个人都可以在没有中介的情况下安全地交换信息和价值。本文将探索Web3的基本概念&#xff0c;去中心化应用&#xff08;D…

pydub AudioSegment实现音频重采样 - python 实现

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” -------------------------------------------------------------…

uniapp/HBuilder X引入weex报错weex is not defined

出现错误&#xff1a; ‍[⁠ReferenceError⁠]‍ {message: "weex is not defined"} 在www.iconfont.cn把想要的图标放进个人项目中并且下载css文件&#xff1a; 进入HBuilder自己创建的项目中添加一个目录common&#xff0c;添加一个文件free-icon.css 把刚才下载…

音频进阶学习八——傅里叶变换的介绍

文章目录 前言一、傅里叶变换1.傅里叶变换的发展2.常见的傅里叶变换3.频域 二、欧拉公式1.实数、虚数、复数2.对虚数和复数的理解3.复平面4.复数和三角函数5.复数的运算6.欧拉公式 三、积分运算1.定积分2.不定积分3.基本的积分公式4.积分规则线性替换法分部积分法 5.定积分计算…

ActiveMQ 反序列化漏洞CVE-2015-5254复现

文章目录 一、产生原因二、利用条件三、利用过程四、PoC&#xff08;概念验证&#xff09;五、poc环境验证使用find搜索vulhub已安装目录打开activeMQ组件查看配置文件端口启动镜像-文件配置好后对于Docker 镜像下载问题及解决办法设置好镜像源地址&#xff0c;进行重启docker查…

主成分分析法大全(包括stata+matlab)

数据简介&#xff1a;主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;&#xff0c; 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量&#xff0c;转换后的这组变量叫主成分。在实际课题中&#xff0c;为了…

qt中tr的使用

在 Qt 中使用 tr 函数对字符串进行翻译时&#xff0c;通常会通过 Qt Linguist 工具来处理翻译。以下是一个基本的步骤说明&#xff0c;展示如何将 QPushButton *btnnew QPushButton(tr("Hello World"),this); 翻译成其他语言&#xff0c;比如中文&#xff1a; 1.创建…

【Unity3D】报错libil2cpp.so找不到问题

mainTemplate.gradle文件末尾添加&#xff1a; **IL_CPP_BUILD_SETUP** 此报错发生在低版本的Unity升级到高版本后&#xff0c;例如Unity2019升级到Unity2021&#xff0c;而Unity2019默认创建的mainTemplate.gradle文件是不包含**IL_CPP_BUILD_SETUP** 因此会导致libil2cpp.so…

GLM4模型详解 - 智谱AI开源大模型全面解析

&#x1f4da; 2024年6月5日,智谱AI在开发者大会上正式开源GLM-4-9B系列大模型。本文将全面解析GLM4的技术特点、部署方案和应用场景。 GLM-4-9B 模型具备了更强大的推理性能、更长的上下文处理能力、多语言、多模态和 All Tools 等突出能力。 “All Tools” 一、模型概述 1.…

嵌入式驱动开发详解17(CAN驱动开发)

文章目录 前言CAN简介CAN收发器CAN协议讲解电气特性传输协议数据帧遥控帧错误帧过载帧帧间隔 同步矫正 CAN控制器CAN控制器模式CAN接收器CAN波特率 CAN设备树分析CAN测试后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发&#xff0c;但是由于部分模块的驱动框架过于复…

【Qt】qt安装

在工作一年之后&#xff0c;还是想做一个Qt的教程&#xff0c;遥想研一刚刚接触Qt&#xff0c;从0到1学习&#xff0c;没有什么参考书籍&#xff0c;网上的资料也不多&#xff0c;幸好Qt官方文档写得好&#xff0c;加上自己肯研究&#xff0c;才堪堪入门。 现在我想自己写一个…

Scala学习记录

dao --------> 数据访问 mode ------> 模型 service ---->业务逻辑 Main -------> UI:用户直接操作&#xff0c;调用Service 改造UI层&#xff1a;

FPGA 17 ,FPGA 与 SR-IOV虚拟化技术,高性能计算与虚拟化技术的结合(FPGA 与 SR-IOV 和 PCI,高性能计算与虚拟化的完美融合)

目录 前言 一. SR-IOV 的起源与发展 1. SR-IOV 的起源与时间线 2. SR-IOV 的诞生原因 3. SR-IOV 的详细介绍 二. SR-IOV 和 PCI 之间的关系 三. PCI 的起源与演进 1. PCI 的起源与时间线 2. PCI 的关键特性 四. FPGA 的独特魅力 1. FPGA 的定义与特性 2. FPGA 的内…

Spring Security 6 系列之二 - 基于数据库的用户认证和认证原理

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级为6.3.0&#xff0c;关键是其风…

ubuntu下anconda装pytorch

1、禁用nouveau sudo vim /etc/modprobe.d/blacklist.conf 在文件最后部分插入以下两行内容 blacklist nouveau options nouveau modeset0 更新系统 sudo update-initramfs -u 重启系统 2、装nvidia驱动 卸载原来驱动 sudo apt-get remove nvidia-* &#xff08;若安装…