UE4委托
委托的基本类型有三种:
- 单播委托
- 多播委托
- 动态委托
单播委托
单播委托指只能绑定一个函数指针的委托,也就是当执行委托时只能触发一个唯一绑定的函数。
单播委托可以绑定一个无返回值或有返回值的函数。
//无返回值函数委托声明
DECLARE_DELEGATE(DelegateName); //无参
DECLARE_DELEGATE_OneParam(DelegateName, Param1Type); //1个参数
DECLARE_DELEGATE_XXXParams(DelegateName, Param1Type, ...); //多参
//有返回值函数委托声明
DECLARE_DELEGATE_RetVal(RetValType, DelegateName); //有返回值无参
DECLARE_DELEGATE_RetVal_OneParam(RetValType, DelegateName, Param1Type); //有返回值,1个参数
DECLARE_DELEGATE_RetVal_XXXParams(RetValType, DelegateName, Param1Type, ...); //有返回值,多参
声明单播委托
DECLARE_DELEGATE(FTestDelegate);
class XXX_API AMyTestActor : public AActor
{
GENERATED_BODY()
public:
AExecuteDelegateActor();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
public:
//单播委托不能声明BlueprintAssignable标识符。动态多播可以声明BlueprintAssignable
FTestDelegate TestDelegate;
}
将函数绑定到单播委托
函数 | 描述 |
---|---|
BindSP | 绑定SharedPtr指向对象的函数,即纯C++类的函数。因为纯C++类一般会使用TSharedPtr用于管理内存。 |
BindThreadSafeSP | 绑定线程安全的共享成员函数委托 |
BindRaw | 纯C++类变量,可以用其绑定委托 |
BindUFunction | 如果成员函数有UFUNCTION宏表示,可用此绑定委托 |
BindUObject | 绑定继承UObject类的成员函数委托 |
BindStatic | 绑定静态(全局)函数委托,BindStatic(&MyClass::StaticFunc); |
BindLambda | 绑定一个Lambda函数 |
BindWeakLambda | 绑定弱引用Lambda函数 |
UnBind | 取消绑定委托 |
//绑定纯C++类函数到委托
TSharedRef<FMyClass> MyClassObj(new FMyClass());
TestDelegate.BindSP(MyClassObj, &FMyClass::XXXFunc);
//绑定UObject子类函数到委托
TestDelegate.BindUObject(this, &UMyUObjectClass::XXXFunc); //当前类内绑定
UMyUObjectClass* MyUObjectClassObj; //其它类内绑定
TestDelegate.BindUObject(MyUObjectClassObj, &UMyUObjectClass::XXXFunc);
委托调用
函数 | 说明 |
---|---|
IsBound | 检查是否绑定一个委托 |
Execute | 不检查绑定而执行委托 |
ExecuteIfBound | 当绑定一个委托时,执行调用 |
多播委托
多播委托可以绑定多个函数,但不能有返回值。
事件是特殊类型的多播委托,它在访问Broadcast()、IsBound()、Celar()函数时受限。
//多播委托
DECLARE_MULTICAST_DELEGATE(DelegateName);
DECLARE_MULTICAST_DELEGATE_ONEPARAM(DelegateName, Param1Type);
DECLARE_MULTICAST_DELEGATE_XXXPARAMS(DelegateName, Param1Type,...);
//动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE(DelegateName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ONEPARAM(DelegateName, Param1Type, Param1Name);
...
绑定多播委托
函数 | 说明 |
---|---|
Add() | 绑定类型参见单播委托,不同之处就是可以绑定多个函数 |
AddStatic() | |
AddRaw() | |
AddSP() | |
AddUObject() | |
Remove() | |
RemoveAll() |
多播执行
Broadcast调用后,会执行所有绑定的委托,但是委托的执行顺序尚未定义。
函数 | 说明 |
---|---|
Broadcast() | 执行所有绑定的委托 |
动态委托
动态委托可以序列化,其函数可以按命名查找,但执行速度比常规委托慢。
动态及动态多播委托的声明宏结尾必须要有分号,所以建议给所有委托都加分号,这样可以统一样式。
//动态委托
DECLARE_DYNAMIC_DELEGATE(DelegateName);
DECLARE_DYNAMIC_DELEGATE_ONEPARAM(DelegateName, Param1Type);
DECLARE_DYNAMIC_DELEGATE_XXXPARAMS(DelegateName, Param1Type,...);
//动态多播委托,可以暴露给蓝图的委托时动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE(DelegateName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ONEPARAM(DelegateName, Param1Type, Param1Name);
动态委托变量(属性)可以作为函数的参数,当我们在蓝图调用函数的同时,可以绑定一个委托了。
DECLARE_DYNAMIC_DELEGATE(FMyDynamicDelegate);
public:
//不能声明为蓝图实现函数,cpp文件必须有实现
UFUNCTION(BlueprintCallable)
void DynDelTestFunc(FMyDynamicDelegate MyDynamicDelegate)
{ //这里为方便说明,直接在声明处定义
//调用出入的动态委托
MyDynamicDelegate.ExecuteIfBound();
}
public:
FMyDynamicDelegate MyDynamicDelegate;
如下图为调用允许绑定动态委托的函数,这就是上面代码的成果:
绑定动态委托
函数 | 说明 |
---|---|
BindDynamic(UserObject, FuncName) | 用于在动态委托上调用BindDynamic()的辅助宏。自动生成函数命名字符串。 |
AddDynamic(UserObject, FuncName) | |
RemoveDynamic(UserObject, FuncName) |
执行动态委托
函数 | 说明 |
---|---|
IsBound() | 用法与单播委托相同,见单播委托 |
Execute() | |
ExecuteIfBound() |
动态多播委托
动态多播委托可以暴露给蓝图使用,并且声明宏中不仅包含变量类型,也包含变量名。如果暴露给蓝图,需要给委托变量的UPROPERTY宏添加BlueprintAssignable标识符
DECLARE_DYNAMIC_MULTICAST_DELEGATE(DelegateName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ONEPARAM(DelegateName, Param1Type, Param1Name);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_XXXPARAM(DelegateName, Param1Type, Param1Name,...);
委托声明示例:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ONEPARAM(FDelegateTest, class AActor*, MyActor);
UPROPERTY(BlueprintAssignable)
FDelegateTest TestDelegate;
应用场景总结
-
单播委托: 当我们只需要在C++中绑定和调用,且只有一个函数需要绑定委托时,可以使用单播委托。
当然,这个委托的绑定和调用可以通过二次函数调用暴露给蓝图。就是绑定和调用的函数再包裹一层,但一般没有必要。
一般常用的就是函数回调时,通过绑定到单播委托进行回调。 -
多播委托: 单播和多播最大不同就是多播可以绑定多个函数,且不能有返回值,其它功能与单播委托一样。
-
动态委托: 顾名思义,就是允许动态绑定,它可以序列化,也就是说可以在蓝图中使用,下面再回顾一下应用场景。
我们可以将动态委托作为变量,在函数中对委托调用,而委托的绑定可以在蓝图中进行。
下图为绑定委托,同时也是调用函数的参数。我们在DynDelTestFunc中对其调用。
典型案例就是SetTimerbyEvent蓝图结点,就是当时间截止时,调用绑定的委托。
-
动态多播委托: 这个更容易理解,它就是蓝图中的事件调度器(EventDispatcher),可以用其在C++和蓝图中绑定和调用委托。
事件
事件后续补充