UE4单播代理
UE4的单播代理
官方文档讲解请点击委托
对于委托,官方解释如下:
委托 在C++对象上引用和执行成员函数的数据类型。
委托 是一种泛型但类型安全的方式,可在C++对象上调用成员函数。可使用委托动态绑定到任意对象的成员函数,之后在该对象上调用函数,即使调用程序不知对象类型也可进行操作。复制委托对象很安全。你也可以利用值传递委托,但这样操作需要在堆上分配内存,因此通常并不推荐。请尽量通过引用传递委托。
理解:
1.委托是一种数据类型,在委托类型的实例化对象上可引用和执行成员函数;
2.定义一种委托类型对象,然后使用将函数绑定到这个代理对象上,之后,便可以通过这个代理对象调用成员函数。
UDELEGATE说明符
委托函数支持与UFunctions相同的说明符,但使用 UDELEGATE 宏而不是 UFUNCTION。例如,以下代码将 BlueprintAuthorityOnly 说明符添加到 FInstigatedAnyDamageSignature 委托中
UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FInstigatedAnyDamageSignature, float, Damage, const UDamageType*, DamageType, AActor*, DamagedActor, AActor*, DamageCauser);
单播代理
单播代理,顾名思义,一次绑定一个函数并执行该函数的委托。
可以根据参数的个数来使用代理。最多可以有9个参数。
代理类型的声明
//单播代理,无参数无返回值,代理名为TestDelegateNoparam
DECLARE_DELEGATE(FTestDelegateNoparam);
//单播代理,两个参数,无返回值,代理名为TestDelegateTwoParams
//这个代理包含两个参数,分别为float和const FStrings&
DECLARE_DELEGATE_TwoParams(FTestDelegateTwoParams, float, const FStrings&);
//单播代理,两个参数,返回值类型为int32, 代理名为TestDelegateTwoParamsRetVal
////这个代理包含两个参数,分别为float和const FStrings&
DECLARE_DELEGATE_RetVal_TwoParams(int32, FTestDelegateTwoParamsRetVal, float, const FStrings&);
代理函数的定义
UCLASS()
class HELLOUE4_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
public:
void FunNoparam();
void FunTwoparamNoRetVal(float a, const FString& s);
int32 FunTwoparamRetVal(float a, const FString& s);
UFUNCTION()
int32 Fun(float a, const FString& s);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
//在类中定义两个代理成员对象
FTestDelegateTwoParamsRetVal DelegateTwoParamsRetVal;
FTestDelegateNoparam DelegateNoparam;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
其cpp文件如下所示
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyActor.h"
// Sets default values
AMyActor::AMyActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor::FunNoparam()
{
}
void AMyActor::FunTwoparamNoRetVal(float a, const FString& s)
{
}
int32 AMyActor::FunTwoparamRetVal(float a, const FString& s)
{
return int32(1);
}
// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//有参数有返回值的代理的绑定
DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);
//绑定后验证并执行
if(DelegateTwoParamsRetVal.IsBound())
DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
//无参数无返回值的代理绑定
DelegateNoparam.ExecuteIfBound();
}
// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
其使用方法可分为三个步骤
1.声明并定义代理,并定义一个代理对象。
声明并定义代理
在这里,就像定义一种类类型一样,这里是定义了一种代理类型,也就是委托类型。
其代理类型为FTestDelegateTwoParamsRetVal,这种类型的代理反悔值为int32类型的,有两个参数,分别为float和FStrings&类型的
DECLARE_DELEGATE_RetVal_TwoParams(int32, FTestDelegateTwoParamsRetVal, float, const FStrings&);
DECLARE_DELEGATE(FTestDelegateNoparam);
代理对象的定义
实例化一个代理对象。
FTestDelegateTwoParamsRetVal DelegateTwoParamsRetVal;
FTestDelegateNoparam DelegateNoparam;
2.代理对象的绑定
在这个步骤中,只是完将代理对象绑定到函数上,并未执行函数.
//绑定继承自UObject类的类里面的成员函数
//其中两个参数,第一个参数为想要使用代理的类的指针
//第二个参数为代理的函数名,传入的是函数地址,故须对函数名引用
DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);
3.执行代理函数
//防止代理未绑定成功而导致程序崩溃,先进行绑定判断
if(DelegateTwoParamsRetVal.IsBound())
//为代理对象传入参数并执行
DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
在执行函数部分,若是无参数类型,还可以如下操作
DelegateNoparam.ExecuteIfBound();
代理与lambda表达式的绑定
在这里,仍然使用前面定义的代理,代理对象的定义,在void AMyActor::BeginPlay()
函数中将代理对象绑定至lambda表达式
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定lambda表达式
//this指针为lambda捕捉本类内所有成员连梁
//由于lambda表达式返回值为int32类型,为了便于说明,return 0;
DelegateTwoParamsRetVal.BindLambda([this](float a, const FString& s) -> int32{
return 0;
});
//代理执行
if(DelegateTwoParamsRetVal.IsBound())
DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
}
绑定原生c++类中方法
首先定义一个原生的c++类中的方法。
首先要知道,c++类中方法只存储一处,只有一份。
class FTestA{
punlic:
int32 Fun(float a, const FString& s){
return 0;
}
}
仍然使用前面定义的代理,代理对象的定义。
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//定义一个类对象
FTestA A;
//代理对象的绑定
//第一个参数为指向要绑定类对象的指针
//第二个参数为要绑定方法的指针
DelegateTwoParamsRetVal.BindRaw(&A,&FTestA::Fun);
//代理执行
if(DelegateTwoParamsRetVal.IsBound())
DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
}
绑定共享指针和线程安全共享指针
在定义原生c++类FTestA中方法的基础上继续绑定共享指针
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定TSharedPtr指向对象的函数,即纯c++类的函数,
TSharedPtr<FTestA> A1 = MakeShareable(new FTestA);
//绑定代理
DelegateTwoParamsRetVal.BindSP(A1.ToSharedRef(), &FTestA::Fun);
}
线程安全共享指针
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定一个线程安全的TSharedPtr包裹着的纯c++类里面的函数,
TSharedPtr<FTestA, ESPMode::ThreadSafe> A2 = MakeShareable(new FTestA);
//绑定代理
DelegateTwoParamsRetVal.BindSP(A2.ToSharedRef(), &FTestA::Fun);
}
绑定静态函数
首先定义静态函数
static int32 Fun1(float a, const FString& s){
return 0;
}
class FTestB{
punlic:
static int32 FunStatic(float a, const FString& s){
return 0;
}
}
在void AMyActor::BeginPlay()
函数中将代理对象绑定至静态函数
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定代理
DelegateTwoParamsRetVal.BindStatic(&Fun1);
}
在void AMyActor::BeginPlay()
函数中将代理对象绑定至类中静态函数
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定代理
DelegateTwoParamsRetVal.BindStatic(&FTestB::FunStatic);
}
绑定至UFUNCTION
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//绑定代理至UFUNCTION
DelegateTwoParamsRetVal.BindUFunction(this, FName("fun"));
}
清除代理
代理绑定并执行完成后,要清除绑定。
void AMyActor::BeginPlay()
{
Super::BeginPlay();
//有参数有返回值的代理的绑定
DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);
//绑定后验证并执行
if(DelegateTwoParamsRetVal.IsBound())
DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
//清除代理
DelegateTwoParamsRetVal.Unbind();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律