UE4 C++ - Proxy

简述 The proxy (or delegate) in UE4 can dynamically bind the function of the class object, similar to the function pointer in C, but the proxy is safer and more reliable. UE4 provides three types of agents, unicast agents, multicast agents, and dynamic agents. 单播代理

详解
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 )
DECLARE_DELEGATE_RetVal( RetValType, DelegateName )

创建一个空的C++工程,命名为ProjectDemo。新建一个继承于APawn的C++类,命名为AMyPawn。

转到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

MyPawn.cpp

上面都是调用BindUObject方法来绑定,代理还提供了其他的绑定方法,都有不同的用法

Create an empty C++ project, named ProjectDemo. Create a new C++ class that inherits from APawn and name it AMyPawn. Go to C++ code, configure pawn in ProjectDemoGameModeBase file, set default pawn in constructor DefaultPawnClass = AMyPawn::StaticClass(); Compile and run, set the level of WorldSettings, set GameMode to AProjectDemoGameModeBase Define and implement the function EventOne() in the APawn class, and bind the event in the SetupPlayerInputComponent function. PlayerInputComponent->BindAction("One", IE_Pressed, this, &AMyPawn::EventOne); When the '1' button is pressed, EventOne() will execute. MyPawn.h
@ @@@Multiple parameters Can declare a delegate from 1 to 8 parameters The macro name is One, Two.....Eight The return value of the delegate
BindLambda 绑定Lambda表达式
BindRaw     代理应用
BindSP Add keyboard event One
BindStatic     Configure GameModel
BindUFunction     binding event
BindUObject     来源

#pragma once #include "CoreMinimal.h" #include "GameFramework/Pawn.h" #include "MyPawn.generated.h" / / Declare no reference agent DECLARE_DELEGATE (DelegateZeroPara) / / Declare a parameter of the proxy DECLARE_DELEGATE_OneParam(DelegateOnePara, FString) / / Declare a proxy for multiple parameters DECLARE_DELEGATE_FiveParams(DelegateFivePara, FString, FString, FString, FString, FString) / / return value agent 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(); //agent DelegateZeroPara zeroParaDelegate; DelegateOnePara oneParaDelegate; DelegateFivePara fiveDelegatePara; DelegateRetVal retValDelegate;                  / / The function that the proxy will bind 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; }; //绑定lambda表达式 DelegateBindLambda.BindLambda([=](FString str) {    if (GEngine) {        GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str + ", " + str);    } });

#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); / / Bind event 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"); } 创建一个原始的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 methodDefine shared pointer variable in .h TSharedPtr<MyClass> myClassPtr; Create a shared pointer in the constructor and bind it myClassPtr = MakeShareable(new MyClass()); DelegateVal.BindSP(myClassPtr.ToSharedRef(), &MyClass::RawFunc);

BindStatic methodDefine a global static function (or normal member static function) Static void staticFunc(FString str) { If (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, str); } } Bind in the constructor DelegateBindStatic.BindStatic(staticFunc);

BindUFunction methodDefine the method UFunc() in the header file and mark it with the macro UFUNCTION //definition UFUNCTION() Void UFunc(FString str) Bind in the constructor, BindUFunction needs to enter the name of the function (FName type) 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 no reference agent
DECLARE_DELEGATE (DelegateZeroPara)
/ / Declare a parameter of the proxy
DECLARE_DELEGATE_OneParam(DelegateOnePara, FString)
/ / Declare a proxy for multiple parameters
DECLARE_DELEGATE_FiveParams(DelegateFivePara, FString, FString, FString, FString, FString)
/ / return value agent
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();

//agent
DelegateOnePara DelegateBindLambda;
DelegateOnePara DelegateBindRaw;
DelegateOnePara DelegateBindSP;
DelegateOnePara DelegateBindStatic;
DelegateOnePara DelegateBindUFunction;

UFUNCTION()
Void UFunc(FString str);
MyClass myClass;
TSharedPtr<MyClass> 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 expression
DelegateBindLambda.BindLambda([=](FString str)
{
If (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, str);
}
});

//C++
DelegateBindRaw.BindRaw(&myClass, &MyClass::RawFunc);

/ / share pointer
myClassPtr = MakeShareable(new MyClass());
DelegateBindSP.BindSP(myClassPtr.ToSharedRef(), &MyClass::RawFunc);

// static function
DelegateBindStatic.BindStatic(staticFunc);

/ / Bind UFUNCTION
DelegateBindUFunction.BindUFunction(this, "UFunc");

}

// Called to bind functionality to input
Void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);

/ / Bind event
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);
}

Compile and run, press ‘1’ key

多播代理Multicast agent can bind multiple functions, all the bound functions will be triggered when the agent runs, and the multicast agent has no return value. The multicast agent's declaration is similar to the unicast agent defines a parameter of the multicast proxy typeDECLARE_MULTICAST_DELEGATE_OneParam(DelegateMulti, FString)defined multicast proxy variable DelegateMulti multiDelegateVal; binding multicast agentmultiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc1); multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc2); multiDelegateVal.AddUObject(this, &AMyPawn::multiDelegateFunc3);Run Multicast AgentmultiDelegateVal.Broadcast("multiDelegate");

来源

MyPawn.h

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyClass.h"
#include "MyPawn.generated.h"
//Multicast agent
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();

//agent
DelegateMulti multiDelegateVal;

//function
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);

/ / Bind event
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);
}
}

//achieve
Void AMyPawn::multiDelegateFunc1(FString str)
{
printString(str + "Func1");
}
Void AMyPawn::multiDelegateFunc2(FString str)
{
printString(str + "Func2");
}
Void AMyPawn::multiDelegateFunc3(FString str)
{
printString(str + "Func3");
}

Compile and run, press '1' key

动态代理The use of dynamic proxy is similar to that of ordinary proxy, but dynamic multicast proxy can be exposed to blueprint and dynamically bind related functions in blueprint. And ordinary agents and dynamic unicast agents can't. Define dynamic multicast proxy type/ Parameters are multicast proxy name, parameter type, parameter name DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDYN_MUL_DEL, FString, InPrar);Note: The name of the dynamic multicast proxy must be F at the beginning, otherwise it will compile the error to define the dynamic multicast proxy variable, and add the macro tag and set it to BlueprintAssignable UPROPERTY(BlueprintAssignable) FDYN_MUL_DEL fDYN_MUL_DEL; Execute multicast agent in function EventOne()fDYN_MUL_DEL.Broadcast("fDYN_MUL_DEL ---"); Save compilation, open the engine editor Create a blueprint class that inherits from the MyPawn class and name it BP_MyPawn. Create a blueprint class that inherits from the ProjectDemoGameModeBase class and name it BP_MyProjectDemoGameModeBase

Configure the Defaule Pawn Class as BP_MyPawn in BP_MyProjectDemoGameModeBase.

Set the WorldSettings of the level, set GameMode to BP_MyProjectDemoGameModeBase

to bind the multicast agent

in BP_MyPawn, press ‘1’