虚幻引擎基础入门(C++) — 【代理说明 09】
前言
- 代理可以解决一对一或一对多的任务分配工作,还可以解决通知问题
- 通过代理完成调用某一个对象的一个函数,而不直接持有该对象的任何指针
- 要调用某个函数,但并不直接去调用,而是通过另一个入口去调用,这就是代理
代理分为:
单播代理(只能进行通知一个人)
多播代理(可以进行多人通知)
动态代理(可以被序列化,体现在可与蓝图进行交互,C++中可以将通知事件进行蓝图广播)
提示:以下是本篇文章正文内容,下面案例可供参考
一、单播代理
-
单播代理只能绑定一个通知对象,无法进行多个对象通知
-
通过宏进行构建,分为两种:
1.有返回类型
2.没有返回类型 -
常用绑定函数:
1.BindUObject:绑定UObject类型对象成员函数的代理
2.BindSP:绑定基于共享引用的成员函数代理
3.BindRaw:绑定原始自定义对象成员函数的代理,操作调用需要注意执行需要检查IsBound
4.BindStatic:绑定全局函数成为代理
5.UnBind:解除绑定代理关系
6.绑定中传递的对象类型必须和函数指针所属类的类型相同,否则绑定会报错 -
调用执行:
1.执行Execute函数之前,需要检查是否存在有效绑定使用函数 IsBound
2.Execute 调用代理通知,不安全
3.ExecuteIfBound 调用代理通知,安全,但是有返回类型的回调函数无法使用此函数执行回调
4.IsBound 检查当前是否存在有效代理绑定 -
构建步骤:
1.通过宏进行声明代理对象类型(根据回调函数选择不同的宏)
2.使用代理类型进行构建代理对象
3.绑定回调对象、操作函数
4.执行代理对象回调//(在.h文件中) //1.构建单播代理(此例以无参无返单播代理为例) //① 单播代理:无参数无返回值单播代理 DECLARE_DELEGATE(CallTest) //② 1个参数的单播代理 DECLARE_DELEGATE_OneParam(Delegate_OneP, int32) //③ 2个参数的单播代理 DECLARE_DELEGATE_TwoParams(Delegate_TwoP, int32, int32) //④ 有返回值,和2个参数的单播代理 DECLARE_DELEGATE_RetVal_TwoParams(float, Delegate_RTwoP, float, float) UCLASS(config=Game) class AUECCharacter : public ACharacter { GENERATED_BODY() public: //2. 声明无参无返的单播代理 CallTest Dnop; //3.创建要绑定到无参无返的单播代理上的函数 void Func(); virtual void BeginPlay(); };
//(在.cpp文件中) void AUECCharacter::Func() { UE_LOG(LogTemp, Log, TEXT("---我是无参无返的单播代理!---")); } void AUECCharacter::BeginPlay() { Super::BeginPlay(); //4.将Func函数绑定到单播代理 Dnop.BindUObject(this, &AUECCharacter::Func); //5.判断单播代理是否绑定 if (Dnop.IsBound()) { //6.调用代理,执行绑定的函数 Dnop.Execute(); } }
输出如下:
二、单播代理
-
无法构建具有返回值的多播代理,只能构建参数
-
广播
调用函数Broadcast,但是调用不保证执行顺序的正确性
-
构建步骤:
1.使用宏构建代理类型
2.使用代理类型构建多播代理对象
3.添加绑定代理
4.执行调用//(在.h文件中) //1.构建多播代理(不可以构建有返回值的) //① 无参的多播代理 DECLARE_MULTICAST_DELEGATE(Delegate_MultiNoP) //② 单播代理:有2个参数的单播代理 DECLARE_MULTICAST_DELEGATE_TwoParams(Delegate_MultiTwoP, int32, int32) UCLASS(config=Game) class AUECCharacter : public ACharacter { GENERATED_BODY() public: //2. 声明多播代理 Delegate_MultiNoP MultiNoP; Delegate_MultiTwoP MultiTwoP; //3.创建要绑定到无参无返的单播代理上的函数 void Func1_MultiNoP(); void Func2_MultiNoP(); void Func1_MultiTwoP(int32 A, int32 B); void Func2_MultiTwoP(int32 C, int32 D); virtual void BeginPlay(); };
//(在.cpp文件中) void AUECCharacter::Func1_MultiNoP() { UE_LOG(LogTemp, Log, TEXT("---------我是无参的多播代理Func1_MultiNoP()!---------")); } void AUECCharacter::Func2_MultiNoP() { UE_LOG(LogTemp, Log, TEXT("---------我是无参的多播代理Func2_MultiNoP()!---------")); } void AUECCharacter::Func1_MultiTwoP(int32 A, int32 B) { UE_LOG(LogTemp, Log, TEXT("---------我是有2个int参AB的多播代理Func1_MultiTwoP!---------")); } void AUECCharacter::Func2_MultiTwoP(int32 C, int32 D) { UE_LOG(LogTemp, Log, TEXT("---------我是有2个int参CD的多播代理Func1_MultiTwoP!---------")); } void AUECCharacter::BeginPlay() { Super::BeginPlay(); //4.将多个函数绑定到多播代理 MultiNoP.AddUObject(this, &AUECCharacter::Func1_MultiNoP); MultiNoP.AddUObject(this, &AUECCharacter::Func2_MultiNoP); MultiTwoP.AddUObject(this, &AUECCharacter::Func1_MultiTwoP); MultiTwoP.AddUObject(this, &AUECCharacter::Func2_MultiTwoP); //5.判断多播代理是否绑定 if (MultiNoP.IsBound()) { //6.调用多播代理,执行绑定的函数 MultiNoP.Broadcast(); } //5.判断多播代理是否绑定 if (MultiTwoP.IsBound()) { //6.调用多播代理,执行绑定的函数 MultiTwoP.Broadcast(2,3); } //清空所有绑定函数 MultiNoP.Clear(); //移除单绑定,需要传递 FDelegateHandle(代理句柄) FDelegateHandle DH_Fun = MultiTwoP.AddUObject(this, &AUECCharacter::Func1_MultiTwoP); MultiTwoP.Remove(DH_Fun); //移除某个对象中的所有函数绑定 MultiTwoP.RemoveAll(this); }
输出如下:
三、动态代理
-
是允许被序列化的数据结构(代理可以被数据化提供给蓝图进行使用),使得可以在.cpp中调用代理广播,并将事件通知到蓝图
-
UE中的大部分通知事件均使用动态代理,方便蓝图操作(如碰撞通知)
-
动态代理无法使用带有返回值的函数进行构建
-
动态代理分为
1.动态单播(但是创建动态单播还不如创建普通的多播,单播无法在蓝图中绑定,无法使用宏BlueprintAssignable修饰)
2.动态多播 -
动态代理与上面单播多播的区别:
1.动态代理的类型名称需要用 F 开头(动态代理实现了机制构建类)
2.动态代理对象类型可以使用UPROPERTY标记;其他代理均无法使用(不加编译可过,调用就会出错)
3.动态代理绑定对象的函数需要使用UFUNCTION进行描述(因为需要跟随代理被序列化) -
构建步骤
1.通过宏进行声明代理对象类型(根据回调函数选择不同的宏)
2.使用代理类型进行构建代理对象
3.绑定回调对象、操作函数
4.执行代理对象回调
总结
以上就是今天要讲的内容,本文仅仅简单介绍了虚幻引擎中的代理说明使用。
至此虚幻引擎基础入门(C++)系列就完毕啦,接下来敬请期待!!!
未完待续!
如有帮助给个关注吧!