UE4的委托(Delegate)使用
委托有点类似函数指针,UE4定义了一大堆的委托方便我们的使用
在DelegateCombinations.h文件中的定义了各种委托
#define DECLARE_DELEGATE( DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, void )
#define DECLARE_MULTICAST_DELEGATE( DelegateName ) FUNC_DECLARE_MULTICAST_DELEGATE( DelegateName, void )
#define DECLARE_EVENT( OwningType, EventName ) FUNC_DECLARE_EVENT( OwningType, EventName, void )
#define DECLARE_DYNAMIC_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
#define DECLARE_DYNAMIC_MULTICAST_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
#define DECLARE_DELEGATE_RetVal( ReturnValueType, DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType )
#define DECLARE_DYNAMIC_DELEGATE_RetVal( ReturnValueType, DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE_RETVAL( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, ReturnValueType, , FUNC_CONCAT( *this ), ReturnValueType )
我在项目中经常使用的有两类委托,单播委托和多播委托
单播委托(DECLARE_DELEGATE)
单播委托,指的是只能绑定一个函数指针的委托,实现一对一的通知。
单播委托的定义是没有“MULTICAST”修饰的委托,如下面这些
DECLARE_DELEGATE
DECLARE_DELEGATE_OneParam
DECLARE_DELEGATE_TwoParams
DECLARE_DELEGATE_ThreeParams
UE4在DelegateCombinations.h文件已经预先帮你声明了从无参数到长达9个参数的委托
怎么使用?
BindUObject
(1)声明委托和定义委托变量
//单播无参数的委托
DECLARE_DELEGATE(FSingleDelagateWithNoParam);FSingleDelagateWithNoParam SingleDelagateWithNoParam;
//单播一个参数的委托
DECLARE_DELEGATE_OneParam(FSingleDelagateWithOneParam, FString);FSingleDelagateWithOneParam SingleDelagateWithOneParam;
(2)绑定函数指针 BindUObject。 这里我经常用BindUObject,绑定的函数指针为UObject或者继承UObject的对象的函数指针
如我定义一个Actor:
.h :
UCLASS()
class MYPROJECT_API ATestActor2 : public AActor
{GENERATED_BODY()public: // Sets default values for this actor's propertiesATestActor2();protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public: // Called every framevirtual void Tick(float DeltaTime) override;private:void Func1();void Func2(FString param);};
.cpp :
void ATestActor2::Func1()
{UE_LOG(LogTemp, Error, TEXT("TestActor2 Func1"));
}void ATestActor2::Func2(FString param)
{UE_LOG(LogTemp, Error, TEXT("TestActor2 Func2 param = %s"), *param);
}
绑定委托:
void ATestActor2::BeginPlay()
{Super::BeginPlay();APlayerController* playerController = GetWorld()->GetFirstPlayerController();if (nullptr == playerController)return;ACharacter* character = playerController->GetCharacter();if (nullptr == character)return;AMyProjectCharacter* myProjectCharacter = Cast(character);if (nullptr == myProjectCharacter)return;myProjectCharacter->SingleDelagateWithNoParam.BindUObject(this, &ThisClass::Func1);myProjectCharacter->SingleDelagateWithOneParam.BindUObject(this, &ThisClass::Func2);
}
这里得注意的是,单播委托如果已经绑定过函数指针,在没有UnBind的情况下如果再次绑定函数指针,会报错。所以经常使用
(3)执行委托,触发相应的对象的函数
SingleDelagateWithNoParam.ExecuteIfBound();
SingleDelagateWithOneParam.ExecuteIfBound(FString("PerformSingleDelagateWithOneParam"));
这里呢,得注意的一点单播委托执行委托函数有:Execute和ExecuteIfBound
我一般用ExecuteIfBound而不是Execute,因为ExecuteIfBound更安全,指的是在委托绑定有效函数指针的前提下才能执行,而Execute如果在委托绑定无效的函数指针的情况下就执行会报错。
运行结果:
(4)移除委托Unbind,移除已经绑定的函数指针
(5)IsBound,判断委托是否已经绑定了函数指针
BindStatic
用于绑定于类的静态函数
UCLASS(config=Game)
class AMyProject6Character : public ACharacter
{static void Test(float a);DECLARE_DELEGATE_OneParam(FAA, float)FAA faa;}faa.BindStatic(&AMyProject6Character::Test);
BindRaw
BindRaw是用于绑定不继承UObject的类或者结构体的对象的方法
CreateUObject
创建委托变量:
DECLARE_DELEGATE_OneParam(FTestDelegate, float);void AMyProject3Character::PrintTestInfo(float Value)
{UE_LOG(LogTemp, Error, TEXT("Value = %f"), Value);
}FTestDelegate MyDel = FTestDelegate::CreateUObject(this, &AMyProject3Character::PrintTestInfo);
其他CreateRaw,CreateStatic同理。
多播委托(DECLARE_MULTICAST_DELEGATE)
多播委托,指的是能绑定多个函数指针的委托,实现一对多的通知。
多播委托的定义是有“MULTICAST”修饰的委托,如下面这些:
DECLARE_MULTICAST_DELEGATE
DECLARE_MULTICAST_DELEGATE_OneParam
DECLARE_MULTICAST_DELEGATE_TwoParams
DECLARE_MULTICAST_DELEGATE_ThreeParams
怎么使用?
AddUObject
(1)声明委托和定义委托变量
//多播无参数委托
DECLARE_MULTICAST_DELEGATE(FMuitiDelagateWithNoParam);FMuitiDelagateWithNoParam MuitiDelagateWithNoParam;//多播一个参数的委托
DECLARE_MULTICAST_DELEGATE_OneParam(FMuitiDelagateWithOneParam, FString);FMuitiDelagateWithOneParam MuitiDelagateWithOneParam;
(2)绑定函数指针 AddUObject。 这里我经常用BindUObject,这个函数绑定的函数指针为UObject或者继承UObject的类对象顶点函数指针.这里可以添加多个函数指针。
.h
UCLASS()
class MYPROJECT_API ATestActor : public AActor
{GENERATED_BODY()public: // Sets default values for this actor's propertiesATestActor();protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public: // Called every framevirtual void Tick(float DeltaTime) override;private:void Func1();void Func2(FString param);
.cpp
void ATestActor::Func1()
{UE_LOG(LogTemp, Error, TEXT("TestActor Func1"));
}void ATestActor::Func2(FString param)
{UE_LOG(LogTemp, Error, TEXT("TestActor Func2 param = %s"), *param);
}
ATestActor::BeginPlay():
void ATestActor::BeginPlay()
{Super::BeginPlay();APlayerController* playerController = GetWorld()->GetFirstPlayerController();if (nullptr == playerController)return;ACharacter* character = playerController->GetCharacter();if (nullptr == character)return;AMyProjectCharacter* myProjectCharacter = Cast(character);if (nullptr == myProjectCharacter)return;myProjectCharacter->MuitiDelagateWithNoParam.AddUObject(this, &ThisClass::Func1);myProjectCharacter->MuitiDelagateWithOneParam.AddUObject(this, &ThisClass::Func2);
}
ATestActor2::BeginPlay():
void ATestActor2::BeginPlay()
{Super::BeginPlay();APlayerController* playerController = GetWorld()->GetFirstPlayerController();if (nullptr == playerController)return;ACharacter* character = playerController->GetCharacter();if (nullptr == character)return;AMyProjectCharacter* myProjectCharacter = Cast(character);if (nullptr == myProjectCharacter)return;myProjectCharacter->MuitiDelagateWithNoParam.AddUObject(this, &ThisClass::Func1);myProjectCharacter->MuitiDelagateWithOneParam.AddUObject(this, &ThisClass::Func2);
}
同时绑定了ATestActor和ATestActor2的函数指针
(3)执行委托,触发函数
MuitiDelagateWithNoParam.Broadcast();MuitiDelagateWithOneParam.Broadcast(FString("PerformMultiDelagateWithOneParam"));
(4)移除函数指针Remove和RemoveAll
Remove的参数为委托AdddUObject返回的句柄FDelegateHandle
AddStatic
用法跟上面的BindStatic对应
动态委托(DECLARE_DYNAMIC_DELEGATE)
动态委托在UE4内置的各种类经常可见,如Actor的鼠标点击(OnBeginCursorOver),开始进入Actor碰撞范围(OnActorBeginOverlap)等等
目前我知道关于动态委托主要是可用于蓝图的委托绑定,如下面所示:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FTestDynamicDelagate, float, Value);UPROPERTY(BlueprintAssignable, Category = "Test")FTestDynamicDelagate OnTestDynamicDelagate;
可以看出得加上 UPROPERTY(BlueprintAssignable, Category = “Test”),这里如果不是动态委托的话会报错
一般来说我们在C++代码使用动态委托绑定一个对象的方法的时候比较喜欢用__Internal_BindDynamic和__Internal_AddDynamic,当然UE4为了调用方便封装了对应的宏:
#define BindDynamic( UserObject, FuncName ) __Internal_BindDynamic( UserObject, FuncName, STATIC_FUNCTION_FNAME( TEXT( #FuncName ) ) )#define AddDynamic( UserObject, FuncName ) __Internal_AddDynamic( UserObject, FuncName, STATIC_FUNCTION_FNAME( TEXT( #FuncName ) ) )
这里比较注意的是用AddDynamic绑定的方法得被“UFUNCTION”标记,否则绑定无效
UFUNCTION()void OnTestBegin(AActor* OverlappedActor, AActor* OtherActor);void AMyActor::OnTestBegin(AActor* OverlappedActor, AActor* OtherActor)
{if (OverlappedActor){UE_LOG(LogTemp, Warning, TEXT("OverlappedActor is %s"), *OverlappedActor->GetName());}if (OtherActor){UE_LOG(LogTemp, Warning, TEXT("OtherActor is %s"), *OtherActor->GetName());}
}void AMyActor::BeginPlay()
{Super::BeginPlay();OnActorBeginOverlap.AddDynamic(this, &AMyActor::OnTestBegin);
}
可返回值委托(DECLARE_DELEGATE_RetVal)
可返回值委托和之前“DECLARE_DELEGATE” “DECLARE_MULTICAST_DELEGATE”差不多,主要的区别是DECLARE_DELEGATE_RetVal这些委托在执行的时候可以返回一个值,如下所示:
DECLARE_DELEGATE_RetVal(float, FTestRetValDelegate);FTestRetValDelegate TestRetValDelegate;float Test();float AMyActor::Test()
{return 1.0f;
}float Value = TestRetValDelegate.Execute();
委托的额外传参数
有时候,我们在委托绑定函数指针的时候,就随便传入一个变量值,UE4的委托也是可以办到的。如下面所示:
//单播无参数的委托
DECLARE_MULTICAST_DELEGATE(FMuitiDelagateWithNoParam);FMuitiDelagateWithNoParam MuitiDelagateWithNoParam;void ATestActor::Func2(FString param)
{UE_LOG(LogTemp, Error, TEXT("TestActor Func2 param = %s"), *param);
}void ATestActor::BeginPlay()
{Super::BeginPlay();APlayerController* playerController = GetWorld()->GetFirstPlayerController();if (nullptr == playerController)return;ACharacter* character = playerController->GetCharacter();if (nullptr == character)return;AMyProjectCharacter* myProjectCharacter = Cast(character);if (nullptr == myProjectCharacter)return;myProjectCharacter->MuitiDelagateWithNoParam.AddUObject(this, &ThisClass::Func2, FString("MuitiDelagateWithNoParam"));}
委托的使用理念
就项目经验而言,我感觉委托就是软件经典模式中的“观察者模式(Observer)”的具体运用,可以很好的松耦合。
比如:玩家死亡,导致UMGWidget的text数值改变,导致敌人获取经验,导致。。。。。。
按正常实现:
class UMGText
{void BeginPlay();void Change();
}class Fighter
{void BeginPlay();void GetExprience();
}Class Person
{void BeginPlay();
void Dead();
}void Person::Dead()
{umgText->Change();fighter->GetExperience();
}
毫无疑问,随着角色死亡影响的事情越来越多,以后我们的Person对象里会保存或者需要获取无数诸如umgText或者fighter的乱七八糟的对象,耦合度很高,
但是有了委托,你可以在Person中声明委托,然后UMGText类和Figther类中的开始函数进行获取Person的委托,然后AddUObject“Change和GetExperience函数”。然后玩家死亡的时候调用委托就行了,实现了很棒的松耦合。
class UMGText
{void BeginPlay();void Change();
}void UMGText::BeginPlay()
{Person person = GetPerson();person->PeronDead.AddUObject(this, &ThisClass::Change);
}class Fighter
{void BeginPlay();void GetExprience();
}void Fighter::BeginPlay()
{Person person = GetPerson();person->PeronDead.AddUObject(this, &ThisClass::GetExprience);
}class Person
{DECLARE_MULTICAST_DELEGATE(FPeronDead);
FPeronDead PeronDead;void Dead();
}void Person::Dead()
{PeronDead.Broadcast();
}
UE4的委托(Delegate)使用相关推荐
- (转)C#中的委托(Delegate)和事件(Event)
转自:http://blog.chinaunix.net/uid-576762-id-2733751.html 把C#中的委托(Delegate)和事件(Event)放到现在讲是有目的的:给下次写的设 ...
- C#的委托(delegate、Action、Func、predicate)
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递.事件是一种特殊的委托. 1.委托的声明 delegate我们常用到的一种声明 delegate至少0个参数,至多32个参 ...
- UE4 委托(代理)简单理解
资料来源于: UE4官方文档 UE4 C++ -- 代理 UE4中的代理(Delegate)使用总结 (UE4 4.20)UE4的委托(Delegate)使用 什么是委托Delegates (网上大部 ...
- C# Delegate(委托)与多线程
C# Delegate(委托)与多线程 很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程. public void ThreadProc(); ...
- Java 利用反射实现C#的委托
一, 观察者模式的缺点 在之前的博文的介绍过观察者模式了. 观察者模式可以让多个观察者同时观察1个被观察者. 也就说被观察者可以1次过执行所有观察者的update()方法. 再通俗d来讲, 就是多个观 ...
- .NET Framework源码研究系列之---Delegate
前言 曾几何时能看到微软产品的源码简直是天方夜谭,不过现在这却成了现实,微软终于对外开放了它的产品的源代码.抛去开源运动与微软之间的世代情仇,抛去微软这一做法的初衷,这总归是件好事,能够让我们拨开云雾 ...
- 一文说通Dotnet的委托
简单的概念,也需要经常看看. 一.前言 先简单说说Delegate的由来.最早在C/C++中,有一个概念叫函数指针.其实就是一个内存指针,指向一个函数.调用函数时,只要调用函数指针就可以了,至于函 ...
- Java与.net的区别delegate和event
There is no delegate concept in Java The right-side C# program may be mimiced with reflection techno ...
- c#中的委托、事件、Func、Predicate、Observer设计模式以及其他
原文地址:[学习笔记]c#中的委托.事件.Func.Predicate.Observer设计模式以及其他 参考资料: 1. 简单谈谈事件与委托 2. C#中的委托和事件(上) 3. C#中的委托和事件 ...
最新文章
- 什么是最佳适应算法?
- redis简单学习3-redis常用命令总结
- 字节一面 —— List 和 Map、Set 的区别
- oracle 02085,OracleDBLink创建和维护以及ORA-02085解决办法
- 用eclipice抓取JS代码
- Unity2018新功能抢鲜 | ShaderGraph实战之全息效果
- Ubuntu 16 apt-get软件包管理错误问题解决记录
- 网络雇佣军 Void Balaur,有组织有纪律,且从不休长假
- 有没有更好的写v =(v == 0?1:0)的方法; [关闭]
- Spark 机器学习拾遗
- 研究生马上要毕业了,可是完全写不出论文,该退学吗?
- LOJ2321「清华集训 2017」无限之环
- 自动售货机支付服务器开发,自动售货机是如何实现移动支付的?
- 用游戏编辑器制作MOD脱颖而出
- 用excel和python做数据分析的优缺点
- 超大附件上传、下载特别慢,怎么破?
- 易基因 | 表观技术:染色质结构构象与DNA互作:ChIP-seq、ATAC-seq
- 职高计算机应用基础学的什么,职高计算机应用基础教法初探
- 深度神经网络的成功应用,深度神经网络技术赋能
- Qt添加.qrc文件和设置exe图标和控件图标