简述
UE4中的代理(或者叫委托)可以动态的绑定类对象的函数,类似于C中的函数指针,但代理更加安全、可靠。UE4提供了三种类型的代理,单播代理,多播代理,动态代理。
单播代理
宏 | 详解 |
DECLARE_DELEGATE( DelegateName ) | 无参无返回值 |
DECLARE_DELEGATE_OneParam(DelegateName, Param1Type ) | 一个参数的委托 |
DECLARE_DELEGATE_TwoParams( DelegateName, Param1Type, Param2Type ) | 两个参数的委托 |
DECLARE_DELEGATE_OneParams( DelegateName, Param1Type, Param2Type ) . . . DECLARE_DELEGATE_EightParams( DelegateName, Param1Type, Param2Type ) |
多个参数的委托 可以声明从1个到8个参数的委托 宏名称依次为One, Two.....Eight |
DECLARE_DELEGATE_RetVal( RetValType, DelegateName ) | 有返回值的委托 |
代理应用
创建一个空的C++工程,命名为ProjectDemo。新建一个继承于APawn的C++类,命名为AMyPawn。
添加键盘事件One
配置GameModel
转到C++代码,在ProjectDemoGameModeBase文件中配置pawn,在构造函数中设置默认pawn
DefaultPawnClass = AMyPawn::StaticClass();
编译运行,设置关卡的WorldSettings,设置GameMode为AProjectDemoGameModeBase
绑定事件
在APawn类中定义并实现函数EventOne(),在SetupPlayerInputComponent函数中绑定该事件。
PlayerInputComponent->BindAction("One", IE_Pressed, this, &AMyPawn::EventOne);
当按下’1’键后,EventOne()将会执行。
源码
MyPawn.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
//声明无参代理
DECLARE_DELEGATE(DelegateZeroPara)
//声明一个参数的代理
DECLARE_DELEGATE_OneParam(DelegateOnePara, FString)
//声明多个参数的代理
DECLARE_DELEGATE_FiveParams(DelegateFivePara, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, DelegateRetVal)
UCLASS()
class PROJECTDEMO_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
void printString(FString str);
void EventOne();
//代理
DelegateZeroPara zeroParaDelegate;
DelegateOnePara oneParaDelegate;
DelegateFivePara fiveDelegatePara;
DelegateRetVal retValDelegate;
//代理将要绑定的函数
void ZeroParaFunc();
void OneParaFunc(FString str);
void FiveParaFunc(FString str1, FString str2, FString str3, FString str4, FString str5);
FString FiveParaFunc();
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
MyPawn.cpp
#include "MyPawn.h"
#include "Engine/GameEngine.h"
// Sets default values
AMyPawn::AMyPawn()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
zeroParaDelegate.BindUObject(this, &AMyPawn::ZeroParaFunc);
oneParaDelegate.BindUObject(this, &AMyPawn::OneParaFunc);
fiveDelegatePara.BindUObject(this, &AMyPawn::FiveParaFunc);
retValDelegate.BindUObject(this, &AMyPawn::FiveParaFunc);
}
// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//绑定事件
PlayerInputComponent->BindAction("One", IE_Pressed, this, &AMyPawn::EventOne);
}
void AMyPawn::EventOne()
{
zeroParaDelegate.ExecuteIfBound();
oneParaDelegate.ExecuteIfBound("oneParaDelegate -----------");
fiveDelegatePara.ExecuteIfBound("FiveParaFunc: Para1", "Para2", "Para3", "Para4", "Para5" );
FString retVal = retValDelegate.Execute();
printString(retVal);
}
void AMyPawn::printString(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, str);
}
}
void AMyPawn::ZeroParaFunc()
{
printString("ZeroParaFunc");
}
void AMyPawn::OneParaFunc(FString str)
{
printString(str);
}
void AMyPawn::FiveParaFunc(FString str1, FString str2, FString str3, FString str4, FString str5)
{
printString(str1 + ", " + str2 + ", " + str3 + ", " + str4 + ", " + str5);
}
FString AMyPawn::FiveParaFunc()
{
return FString("FiveParaFunc");
}
编译运行,按下‘1’键
代理绑定
上面都是调用BindUObject方法来绑定,代理还提供了其他的绑定方法,都有不同的用法
方法 | 详解 |
BindLambda | 绑定Lambda表达式 |
BindRaw | 绑定到一个原始的C++类对象函数 |
BindSP | 绑定到一个共享指针函数 |
BindStatic | 绑定到全局静态函数 |
BindUFunction | 绑定由UFUNCTION标记的函数 |
BindUObject | 绑定继承UObject类的对象函数 |
BindLambda方法
//绑定lambda表达式
DelegateBindLambda.BindLambda([=](FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str + ", " + str);
}
});
BindRaw方法
创建一个原始的C++类,即继承None的类,命名为MyClass。
定义并实现方法
void MyClass::RawFunc(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str);
}
}
定义MyClass类对象
MyClass myClass;
在构造函数中绑定
DelegateBindRaw.BindRaw(&myClass, &MyClass::RawFunc);
BindSP方法
在.h中定义共享指针变量
TSharedPtr
在构造函数中创建共享指针,并绑定
myClassPtr = MakeShareable(new MyClass());
DelegateVal.BindSP(myClassPtr.ToSharedRef(), &MyClass::RawFunc);
BindStatic方法
定义一个全局静态函数(或者普通的成员静态函数)
static void staticFunc(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str);
}
}
在构造函数中绑定
DelegateBindStatic.BindStatic(staticFunc);
BindUFunction方法
在头文件中定义方法UFunc(),并用宏UFUNCTION标记
//定义
UFUNCTION()
void UFunc(FString str)
在构造函数中绑定,BindUFunction需输入函数的名称(FName类型)
DelegateBindUFunction.BindUFunction(this, "UFunc");
源码
MyPawn.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyClass.h"
#include "MyPawn.generated.h"
static void staticFunc(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str);
}
}
//声明无参代理
DECLARE_DELEGATE(DelegateZeroPara)
//声明一个参数的代理
DECLARE_DELEGATE_OneParam(DelegateOnePara, FString)
//声明多个参数的代理
DECLARE_DELEGATE_FiveParams(DelegateFivePara, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, DelegateRetVal)
UCLASS()
class PROJECTDEMO_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
void printString(FString str);
void EventOne();
//代理
DelegateOnePara DelegateBindLambda;
DelegateOnePara DelegateBindRaw;
DelegateOnePara DelegateBindSP;
DelegateOnePara DelegateBindStatic;
DelegateOnePara DelegateBindUFunction;
UFUNCTION()
void UFunc(FString str);
MyClass myClass;
TSharedPtr myClassPtr;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
MyPawn.cpp
#include "MyPawn.h"
#include "Engine/GameEngine.h"
// Sets default values
AMyPawn::AMyPawn()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//lambda表达式
DelegateBindLambda.BindLambda([=](FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, str);
}
});
//C++
DelegateBindRaw.BindRaw(&myClass, &MyClass::RawFunc);
//共享指针
myClassPtr = MakeShareable(new MyClass());
DelegateBindSP.BindSP(myClassPtr.ToSharedRef(), &MyClass::RawFunc);
//静态函数
DelegateBindStatic.BindStatic(staticFunc);
//绑定UFUNCTION
DelegateBindUFunction.BindUFunction(this, "UFunc");
}
// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//绑定事件
PlayerInputComponent->BindAction("One", IE_Pressed, this, &AMyPawn::EventOne);
}
void AMyPawn::EventOne()
{
DelegateBindLambda.ExecuteIfBound("lamdab Func");
DelegateBindRaw.ExecuteIfBound("RawFunc");
DelegateBindSP.ExecuteIfBound("SPFunc");
DelegateBindStatic.ExecuteIfBound("staticFunc");
DelegateBindUFunction.ExecuteIfBound("UFunction");
}
void AMyPawn::printString(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, str);
}
}
void AMyPawn::UFunc(FString str)
{
printString(str);
}
编译运行,按下‘1’键
多播代理
多播代理可以绑定多个函数,代理运行时将触发所有绑定的函数,多播代理没有返回值。多播代理的声明与单播代理相似
定义一个参数的多播代理类型
DECLARE_MULTICAST_DELEGATE_OneParam(DelegateMulti, FString)
定义多播代理变量
DelegateMulti multiDelegateVal;
绑定多播代理
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc1);
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc2);
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc3);
运行多播代理
multiDelegateVal.Broadcast("multiDelegate");
源码
MyPawn.h
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyClass.h"
#include "MyPawn.generated.h"
//多播代理
DECLARE_MULTICAST_DELEGATE_OneParam(DelegateMulti, FString)
UCLASS()
class PROJECTDEMO_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
void printString(FString str);
void EventOne();
//代理
DelegateMulti multiDelegateVal;
//函数
UFUNCTION(BlueprintCallable, Category = "DelegateMulti")
void multiDelegateFunc1(FString str);
UFUNCTION(BlueprintCallable, Category = "DelegateMulti")
void multiDelegateFunc2(FString str);
UFUNCTION(BlueprintCallable, Category = "DelegateMulti")
void multiDelegateFunc3(FString str);
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
MyPawn.cpp
#include "MyPawn.h"
#include "Engine/GameEngine.h"
// Sets default values
AMyPawn::AMyPawn()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc1);
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc2);
multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc3);
}
// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//绑定事件
PlayerInputComponent->BindAction("One", IE_Pressed, this, &AMyPawn::EventOne);
}
void AMyPawn::EventOne()
{
multiDelegateVal.Broadcast("multiDelegate");
}
void AMyPawn::printString(FString str)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, str);
}
}
//实现
void AMyPawn::multiDelegateFunc1(FString str)
{
printString(str + "Func1");
}
void AMyPawn::multiDelegateFunc2(FString str)
{
printString(str + "Func2");
}
void AMyPawn::multiDelegateFunc3(FString str)
{
printString(str + "Func3");
}
编译运行,按下‘1’键
动态代理
动态代理的使用方法和普通代理相似,不过动态多播代理可以暴露给蓝图,在蓝图中动态绑定相关的函数,而普通的代理和动态单播代理则不行。
定义动态多播代理类型
//参数分别为多播代理名称,参数类型,参数名称
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDYN_MUL_DEL, FString, InPrar);
注:动态多播代理的名称开头须为F,否则会编译报错
定义动态多播代理变量,并添加宏标记,并设置为BlueprintAssignable
UPROPERTY(BlueprintAssignable)
FDYN_MUL_DEL fDYN_MUL_DEL;
在函数EventOne()中执行多播代理
fDYN_MUL_DEL.Broadcast("fDYN_MUL_DEL ---");
保存编译,打开引擎编辑器
新建继承于MyPawn类的蓝图类,命名为BP_MyPawn。新建继承于ProjectDemoGameModeBase类的蓝图类,命名为BP_MyProjectDemoGameModeBase
在BP_MyProjectDemoGameModeBase中配置Defaule Pawn Class为BP_MyPawn。
设置关卡的WorldSettings,设置GameMode为BP_MyProjectDemoGameModeBase
在BP_MyPawn绑定多播代理