虚幻学习笔记17—C++委托(单播)

一、前言

        相比“代理”这个名词我更喜欢叫“委托”,虚幻的委托分为三类,分别为单播、多播和动态多播。单播顾名思义就是一次只能绑定一个函数的委托,多播能一次性绑定多个,动态多播即可以在蓝图中进行动态的绑定且可以绑定多个。

        使用的虚幻版本为5.2.1,VS版本为2022。

二、实现

        在虚幻中创建一个Actor类,命名为“DelegateActor”类。

 1、定义类型

单播可以定义带参数、返回值和参数+返回值三类委托,如下代码所示,分别定义了这三类单播委托,所有的说明见注释部分

DECLARE_DELEGATE(NoParamDelegate);//没有参数没有返回值的委托,委托名称为“NoParamDelegate”
DECLARE_DELEGATE_OneParam(OneParamDelegate, FString);//一个参数没有返回值的委托,名称为“OneParamDelegate”
DECLARE_DELEGATE_TwoParams(TwoParamDelegate, FString, int32);//两个参数没有返回值的委托,名称为“TwoParamDelegate”
DECLARE_DELEGATE_RetVal(FString, OnlyRetDelegate);//仅仅是返回值的委托,名称为“OnlyRetDelegate”
DECLARE_DELEGATE_RetVal_OneParam(FString, RetOneParamDelegate, FString);//定义了带参数和返回值的委托,第一个参数为返回值,第二个为委托名称,第三个为返回值
2、声明委托类型变量

上述定义的可以将其看作是一个类型定义,要真正使用还需要在类中声明该类型的变量,如下所示

	//单播代理变量的声明NoParamDelegate NoParamDelegate;OneParamDelegate OneParamDelegate;TwoParamDelegate TwoParamDelegate;OnlyRetDelegate OnlyRetDelegate;RetOneParamDelegate RetOneParamDelegate;

注:C++中居然允许变量名称可以和委托名称一样,这样带来的问题是后续想再定义一个同类型的委托变量就会报错。如图2.1.1所示

图2.1.1
因此最好还是将变量名称不要定义成和类型名称一样
	NoParamDelegate NoParamDelegate1;NoParamDelegate NoParamDelegate2;OneParamDelegate OneParamDelegate1;TwoParamDelegate TwoParamDelegate1;OnlyRetDelegate OnlyRetDelegate1;
3、定义委托需要绑定的函数

        定义的函数要和对应的委托保持一致的返回值和参数。

	//单播代理绑定函数定义void NoParamDelegateFunc1();void NoParamDelegateFunc2();void OneParamDelegateFunc(FString strVal);void TwoParamDelegateFunc(FString strVal, int32 intVal);FString OnlyRetDelegateFunc();FString RetOneParamDelegateFunc(FString strVal);

其实现代码如下,注:FString作为返回值时,不能直接返回声明的FString类型变量tempStr,必须返回FString(tempStr)这样的结构。


void ADelegateActor::NoParamDelegateFunc1()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc1")));
}void ADelegateActor::NoParamDelegateFunc2()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc2")));
}void ADelegateActor::OneParamDelegateFunc(FString strVal)
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("OneParamDelegateFunc:%s"), *strVal));
}void ADelegateActor::TwoParamDelegateFunc(FString strVal, int32 intVal)
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc:%s,%d"), *strVal, intVal));
}
FString ADelegateActor::OnlyRetDelegateFunc()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("OnlyRetDelegate")));return FString();
}FString ADelegateActor::RetOneParamDelegateFunc(FString strVal)
{FString tempStr = strVal.Append("RetOneParamDelegateFunc");return FString(tempStr);
}
4、 最后在构造函数或其他初始函数中进行绑定

            单播委托的绑定如下所示

	NoParamDelegate1.BindUObject(this, &ADelegateActor::NoParamDelegateFunc1);NoParamDelegate2.BindUObject(this, &ADelegateActor::NoParamDelegateFunc2);OneParamDelegate1.BindUObject(this, &ADelegateActor::OneParamDelegateFunc);TwoParamDelegate1.BindUObject(this, &ADelegateActor::TwoParamDelegateFunc);OnlyRetDelegate1.BindUObject(this, &ADelegateActor::OnlyRetDelegateFunc);RetOneParamDelegate1.BindUObject(this, &ADelegateActor::RetOneParamDelegateFunc);
5、执行

        通过如下代码进行执行,编译代码通过后,在编辑器中创建该类的蓝图并将其拖放到场景中运行即可看到每个函数的打印消息。

	NoParamDelegate1.ExecuteIfBound();NoParamDelegate2.ExecuteIfBound();OneParamDelegate1.ExecuteIfBound("TestStr");TwoParamDelegate1.ExecuteIfBound("TwoParam", 22222);OnlyRetDelegate1.Execute();//这个和上面的不一样FString tempStr = RetOneParamDelegate1.Execute("this is:");GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, tempStr);

注:带返回值的和不带返回值的执行函数是不一样的,这点官方文档也未作详细说明,敲代码的时候这个执行函数也不会提示,也是比较坑。

6、解绑与绑定新的函数

        解绑有点坑,官方文档写的是"UnBind",而实际上是“Unbind()"函数,而在使用了番茄助手的情况下又没有提示,敲完”UnBind“后一直报错

	NoParamDelegate.Unbind();

绑定新的函数,直接像之前一样添加绑定,绑定后会覆盖掉之前的,在执行的时候只会执行新的绑定函数。

	NoParamDelegate.BindUObject(this, &ADelegateActor::NoParamDelegateFunc2);

如图6.1.1所示为官方给定的其他绑定函数,不过官方没有案例说明,只有如图简单的介绍性说明,这点和Unity是没法比,所以针对每一个绑定只能自己去尝试使用一下。

图6.1.1

1)Bind

        绑定现有的委托对象,提示没有这个函数,暂时还不知道怎么使用。

2)BindStatic

        需要定义一个静态函数然后进行绑定,执行方法不变。

//定义
static void StaticNoParamDelegate();//实现
void StaticNoParamDelegate()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("BindStatic")));
}
//绑定全局静态函数
NoParamDelegate1.BindStatic(StaticNoParamDelegate);//绑定类中的静态函数
NoParamDelegate1.BindStatic(类名::静态函数名称);

注意:可以绑定类和全局的静态函数,这里和之前BindUObject中不同的是参数前不用”&“运算符。

3)BindRaw

       绑定不是继承虚幻UObject类的函数,这个和BindUObject正好相反。首先需要在虚幻中创建一个不继承任何东西的类

然后在其类中顶一个不带参数和返回值的函数 

//函数定义void Raw_NoParamDelegateFunc();//函数实现
void MyRawClass::Raw_NoParamDelegateFunc()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("Raw_NoParamDelegateFunc")));
}

注:在不经常虚幻基础类的其他类中也可以使用虚幻引擎的打印屏幕函数。

绑定这个函数

	MyRawClass* tempRawClass = new MyRawClass();NoParamDelegate1.BindRaw(tempRawClass, &MyRawClass::Raw_NoParamDelegateFunc);

注意绑定的参数第一个是对象指针,如下所示是另一种创建对象方式(这都是C++的基础,(;´༎ຶД༎ຶ`) 

	MyRawClass tempRawClass;NoParamDelegate1.BindRaw(&tempRawClass, &MyRawClass::Raw_NoParamDelegateFunc);

4)BindLambda

绑定一个Lambda表达式,Lambda表达式是一个匿名函数片段,即可以在函数内单独定一个一段函数,代码如下,使用关键字auto,其中”auto LambdaDelegateFunc = []()->void“,()里面可以添加参数,返回值可以将void类型改成其他返回值类型。

	auto LambdaDelegateFunc = []()->void{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("LambdaDelegateFunc")));};NoParamDelegate1.BindLambda(LambdaDelegateFunc);

Lambda表达式也可以直接写在要绑定的方法参数里,这个比上面的更简便,完全没有函数名

	NoParamDelegate1.BindLambda([]()->void{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("LambdaDelegateFunc")));});

5)BindSP

        绑定SharedPtr(智能指针)指向对象的函数,即纯C++类(非继承虚幻基类的类)的函数。因为纯C++类一般会使用TSharedPtr用于管理内存。

	//绑定智指针TSharedRef<MyRawClass> ObjSP1 = MakeShareable(new MyRawClass());NoParamDelegate1.BindSP(ObjSP1, &MyRawClass::Raw_NoParamDelegateFunc);

注意,这段绑定函数不要和之前的函数一样放在构造函数中,否则会出现绑定不成功的情况。

6)BindUObject

       绑定继承了虚幻引擎基类的类成员函数,前面案例中已经介绍使用,不再赘述。 

三、总结

3.1、单播可以定义三类委托,分别为带参数、返回值和参数+返回值。

3.2、声明委托的时候变量名称最好不要喝类型名称一样。

3.3、要绑定的函数和定义的委托在参数和返回值上要一致。

3.4、带返回值的和不带返回值的执行函数是不一样的。

3.5、解绑不是"UnBind",而实际上是“Unbind()"函数。

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

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

相关文章

mybatisplus使用雪花id通过swagger返回ID时精度丢失问题

在使用mybatisplus自带雪花的时候会发现返回的ID是19位的长度&#xff0c;因此在通过swagger页面展示的时候会发现后端返回的和页面展示的ID不一致问题。是因为精度丢失的问题。因此需要更改雪花ID的长度跟踪进去&#xff1a;发现是DefaultIdentifierGenerator类实现了Identifi…

蓝桥杯专题-真题版含答案-【扑克牌排列】【放麦子】【纵横放火柴游戏】【顺时针螺旋填入】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

Python Pandas 如何给DataFrame增加一行/多行 数据(第6讲)

Python Pandas 如何给DataFrame增加一行/多行 数据(第6讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ…

GZ015 机器人系统集成应用技术样题2-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题2 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

QT-坦克大战游戏

QT-坦克大战游戏 一、演示效果二、关键程序三、下载链接 一、演示效果 二、关键程序 #include "score.h" Score::Score(){health30; maxHealthhealth;QLabel *label1 new QLabel(this);label1->setFrameStyle(QFrame::Plain | QFrame::Box);label1->setStyle…

将 Github token 添加至远程仓库

将 Github token 添加至远程仓库后便于每次 push 重复输入的麻烦 首先,将已生成的 token 记录(注:生成后的 token 确认后便无法查看只能重新生成)并找到对应的项目 git 本地文件路径下 其次,将其与项目所关联,按如下格式配置即可 token 格式类似于 ghp_CAxxxxxxxxxxxxxxxxxGx5j…

竞赛保研 python+深度学习+opencv实现植物识别算法系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

AI人工智能在建筑智能化工程设计的应用

AI人工智能在建筑智能化工程设计的应用 相关政策&#xff1a; 建筑智能化工程设计资质是为了合理设计各种智能化系统&#xff0c;让它们有机地结合成为有效的整体作用。在工程设计标准中&#xff0c;智能化资质设计全称为建筑智能化系统专项设计资质。企业一旦具备智能化设计资…

vue 使用 Echarts做地图及飞线效果

前言&#xff1a; 效果图 一. 项目中安装以及引入Echarts 1.1 npm 命令安装echarts库 npm install echarts --save 1.2 yarn命令安装echarts库 yarn add echarts 1.3 引用 a. 在使用页面上引入 在Vue组件的script标签中引入echarts库 使用 echarts import * as echarts f…

动态面板简介以及ERP原型图案列

动态面板简介以及ERP原型图案列 1.Axure动态面板简介2.使用Axure制作ERP登录界面3.使用Asure完成左侧菜单栏4.使用Axuer完成公告栏5.使用Axuer完成左边侧边栏 1.Axure动态面板简介 在Axure RP中&#xff0c;动态面板是一种强大的交互设计工具&#xff0c;它允许你创建可交互的…

mysql数据库损坏后重装,数据库备份

重装 先卸载 sudo apt-get remove --purge mysql-server mysql-client mysql-common sudo apt-get autoremove sudo apt-get autoclean 然后重新安装MySQL: sudo apt-get install mysql-server mysql-client 首先要先使用无密码登录数据库一定要使用 sudo mysql -uroo…

C#Winform菜鸟驿站管理系统-快递信息管理界面多条件查询实现方法

1&#xff0c;具体的页面设计如下&#xff0c; 2&#xff0c; 关于下拉框数据填充实现&#xff0c;站点选择代码实现如下&#xff0c;因为站点加载在很多界面需要用到&#xff0c;所以把加载站点的方法独立出来如下&#xff1b; /// <summary>/// 加载站点下拉框/// <…

SaaS行业分析

文章目录 什么是SaaS ?SaaS的标准定义什么是软件即服务&#xff1f;SaaS与传统软件的区别 &#xff1f; SaaS行业分析你知道最赚钱的行业是什么&#xff1f;互联网带给企业的变化 SaaS与PaaS、IaaS的区别&#xff1f;IaaS&#xff08;Infrastructure as a Service&#xff09;…

配置VRRP负载分担示例

一、组网需求&#xff1a; HostA和HostC通过Switch双归属到SwitchA和SwitchB。为减轻SwitchA上数据流量的承载压力&#xff0c;HostA以SwitchA为默认网关接入Internet&#xff0c;SwitchB作为备份网关&#xff1b;HostC以SwitchB为默认网关接入Internet&#xff0c;SwitchA作为…

基于YOLOv8深度学习的高精度车辆行人检测与计数系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

介绍一款低代码数据可视化平台

一、前言 随着企业数字化拉开序幕&#xff0c;低代码( Low Code Development)开发的概念开始火起来&#xff0c;即用少量的代码就能开发复杂的业务系统。然后更进一步&#xff0c;由此又催生出一个新的概念&#xff1a;无代码开发( No Code Development)。 低代码和无代码开发平…

Docker单点部署 Elasticsearch + Kibana [8.11.3]

文章目录 一、Elasticsearch二、Kibana三、访问四、其他 Elasticsearch 和 Kibana 版本一般需要保持一致才能一起使用&#xff0c;但是从 8.x.x开始&#xff0c;安全验证不断加强&#xff0c;甚至8.x.x之间的版本安全验证方法都不一样&#xff0c;真的很恼火。 这里记录一次成…

娱乐新拐点:TikTok如何改变我们的日常生活?

在数字时代的浪潮中&#xff0c;社交媒体平台不断涌现&#xff0c;其中TikTok以其独特的短视频内容在全球范围内掀起了一场娱乐革命。本文将深入探讨TikTok如何改变我们的日常生活&#xff0c;从社交互动、文化传播到个人创意表达&#xff0c;逐步改写了娱乐的新篇章。 短视频潮…

idea2023解决右键没有Servlet的问题

复制Servlet Class.java中的文件。 回到文件&#xff0c;然后点击小加号 然后输入刚刚复制的东西&#xff1a; 3. 此时右键有servlet。 4. 然后他让你输入下面两个框&#xff1a; JAVAEE TYPE中输入Servlet Class Name 表示你要创建的Servlet类的名称是什么。自己起名字。然后…

手动添加Git Bash Here到右键菜单(超详细)

通过WindowsR快捷键可以打开“运行窗口”&#xff0c;在“窗口”中输入“regedit”&#xff0c;点击“确定”打开注册表。 依次进入HKEY_CLASSES_ROOT —-》 Directory —-》Background —-》 shell 路径为Computer\HKEY_CLASSES_ROOT\Directory\Background\shell 3.在“s…