UE4 C++ —— 代理

简述
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。

UE4 C++ —— 代理_第1张图片
添加键盘事件One

配置GameModel
转到C++代码,在ProjectDemoGameModeBase文件中配置pawn,在构造函数中设置默认pawn
DefaultPawnClass = AMyPawn::StaticClass();
编译运行,设置关卡的WorldSettings,设置GameMode为AProjectDemoGameModeBase

UE4 C++ —— 代理_第2张图片

绑定事件
在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;
在构造函数中创建共享指针,并绑定
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’键

UE4 C++ —— 代理_第3张图片

 

多播代理
多播代理可以绑定多个函数,代理运行时将触发所有绑定的函数,多播代理没有返回值。多播代理的声明与单播代理相似
定义一个参数的多播代理类型
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

UE4 C++ —— 代理_第4张图片

在BP_MyProjectDemoGameModeBase中配置Defaule Pawn Class为BP_MyPawn。

UE4 C++ —— 代理_第5张图片

设置关卡的WorldSettings,设置GameMode为BP_MyProjectDemoGameModeBase

UE4 C++ —— 代理_第6张图片

在BP_MyPawn绑定多播代理

UE4 C++ —— 代理_第7张图片编译运行,按下‘1’键

你可能感兴趣的:(UE4,C++)