UE4代理委托(代理,动态代理,单播,多播)

官方例子https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/Delegates

创建基于官方第三人称模版C++工程,项目名字:MyTP,以下例子基于该工程实现

代理委托就是函数指针(类成员函数指针),函数指针指向函数地址,然后调用该函数指针,实现所需效果。

1、代理声明、绑定、执行(单播)

MyTPCharacter.h :

 

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyTPCharacter.generated.h"


//声明无参代理
DECLARE_DELEGATE(D_NoParam)
//声明1个参数的代理
DECLARE_DELEGATE_OneParam(D_1Param, FString)
//声明5个参数的代理
DECLARE_DELEGATE_FiveParams(D_5Param, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, D_RV)


UCLASS(config=Game)
class AMyTPCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	AMyTPCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;


	//定义代理
	D_NoParam DelegateNoParam;
	D_1Param Delegate1Param;
	D_5Param Delegate5Param;
	D_RV DelegateRV;

	//绑定到代理的函数
	void FuncNoParam();
	void Func1Param(FString Str);
	void Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5);
	FString FuncRV();


	void OnRunEvent();//绑定到Q键函数,执行所有代理
	void PrintScreenStr(FString Str);//打印日志到屏幕函数

protected:

	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};

MyTPCharacter.cpp:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "MyTPCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"

#include "Engine/GameEngine.h"


//
// AMyTPCharacter

AMyTPCharacter::AMyTPCharacter()
{
	
	 DelegateNoParam.BindUObject(this,&AMyTPCharacter::FuncNoParam);
	 Delegate1Param.BindUObject(this, &AMyTPCharacter::Func1Param);
	 Delegate5Param.BindUObject(this, &AMyTPCharacter::Func5Param);
	 DelegateRV.BindUObject(this, &AMyTPCharacter::FuncRV);
	
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}

//
// Input

void AMyTPCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);

	PlayerInputComponent->BindAction("RunEvent", IE_Pressed, this, &AMyTPCharacter::OnRunEvent);



	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &AMyTPCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyTPCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &AMyTPCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &AMyTPCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &AMyTPCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &AMyTPCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AMyTPCharacter::OnResetVR);

	
}


void AMyTPCharacter::PrintScreenStr(FString Str)
{
	if (GEngine) 
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Red, Str);
	}
}

void AMyTPCharacter::OnRunEvent()
{
	DelegateNoParam.ExecuteIfBound();
	Delegate1Param.ExecuteIfBound("Delegate1Param!");
	Delegate5Param.ExecuteIfBound("1Param!", "2Param!", "3Param!", "4Param!", "5Param!");
	FString CurRV = DelegateRV.Execute();
	PrintScreenStr(CurRV);
	
}
void AMyTPCharacter::FuncNoParam()
{
	PrintScreenStr("NoParam");
}
void AMyTPCharacter::Func1Param(FString Str)
{
	PrintScreenStr(Str);
}
void AMyTPCharacter::Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5)
{
	PrintScreenStr(Str1 + " "+ Str2 + " " + Str3 +" "+ Str4 + " " + Str5);
}
FString AMyTPCharacter::FuncRV()
{
	return  FString("FuncRV");
}

void AMyTPCharacter::OnResetVR()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}

void AMyTPCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void AMyTPCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void AMyTPCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void AMyTPCharacter::MoveRight(float Value)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}

绑定Q键如下图:

启动 游戏,摁下Q键盘,屏幕信息如下:

2、代理各种绑定(单播)

还是基于步骤1,编辑器创建一个基于None的类,名字:MyTest

MyTest.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

/**
 * 
 */
class MYTP_API MyTest
{
public:
	MyTest();
	~MyTest();
	void TestFunc(FString Str);

};

MyTest.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyTest.h"
#include "Engine/GameEngine.h"

MyTest::MyTest()
{
}

MyTest::~MyTest()
{
}
void MyTest::TestFunc(FString Str)
{
	if (GEngine) 
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, Str);
	}
}

MyTPCharacter.h :

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyTest.h"
#include "MyTPCharacter.generated.h"



//声明无参代理
DECLARE_DELEGATE(D_NoParam)
//声明1个参数的代理
DECLARE_DELEGATE_OneParam(D_1Param, FString)
//声明5个参数的代理
DECLARE_DELEGATE_FiveParams(D_5Param, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, D_RV)


static void Static_Func(FString Str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, Str);
	}
}



UCLASS(config=Game)
class AMyTPCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	AMyTPCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;


	//定义代理
	D_NoParam DelegateNoParam;
	D_1Param Delegate1Param;
	D_5Param Delegate5Param;
	D_RV DelegateRV;

	//绑定到代理的函数
	void FuncNoParam();
	void Func1Param(FString Str);
	void Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5);
	FString FuncRV();

	void OnRunEvent();//绑定到Q键函数,执行所有代理
	void PrintScreenStr(FString Str);//打印日志到屏幕函数

	//定义多种绑定
	D_1Param DelegateLambda;
	D_1Param DelegateRaw;
	D_1Param DelegateSP;
	D_1Param DelegateStatic;
	D_1Param DelegateUFunction;

	UFUNCTION()//可以声明BlueprintCallable等其他标记
		void TestUFunc(FString str);
	MyTest MyT;
	TSharedPtr<MyTest> MyT_SPtr;
	
protected:

	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};

MyTPCharacter.cpp:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "MyTPCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"

#include "Engine/GameEngine.h"
#include "MyTest.h"

//
// AMyTPCharacter

AMyTPCharacter::AMyTPCharacter()
{
	
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)


	DelegateNoParam.BindUObject(this, &AMyTPCharacter::FuncNoParam);//this只能是继承自UObject的类,绑定继承UObject类的对象函数
	Delegate1Param.BindUObject(this, &AMyTPCharacter::Func1Param);
	Delegate5Param.BindUObject(this, &AMyTPCharacter::Func5Param);
	DelegateRV.BindUObject(this, &AMyTPCharacter::FuncRV);


	//Lambda表达式
	auto LambdaFunc = [&](FString str)
	{
		if (GEngine) {
			GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
		}
	};
	DelegateLambda.BindLambda(LambdaFunc);//绑定lambda表达式
	DelegateRaw.BindRaw(&MyT, &MyTest::TestFunc);//绑定到一个原始的C++类函数绑定到一个原始的C++指针全局函数代理上。原始指针不使用任何引用,所以如果从代理的底层删除了该对象,那么调用它可能是不安全的。因此,当调用Execute()时一定要小心!

	
	MyT_SPtr = MakeShareable(new MyTest());
	DelegateSP.BindSP(MyT_SPtr.ToSharedRef(), &MyTest::TestFunc);//绑定一个基于共享指针的成员函数代理。共享指针代理保持到您的对象的弱引用。您可以使用 ExecuteIfBound() 来调用它们。
	DelegateStatic.BindStatic(Static_Func);//绑定全局静态函数
	DelegateUFunction.BindUFunction(this,"TestUFunc");//绑定this指向对象类蓝图函数

}

//
// Input

void AMyTPCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);

	PlayerInputComponent->BindAction("RunEvent", IE_Pressed, this, &AMyTPCharacter::OnRunEvent);



	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &AMyTPCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyTPCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &AMyTPCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &AMyTPCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &AMyTPCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &AMyTPCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AMyTPCharacter::OnResetVR);

	
}


void AMyTPCharacter::PrintScreenStr(FString Str)
{
	if (GEngine) 
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Red, Str);
	}
}

void AMyTPCharacter::OnRunEvent()
{
	DelegateNoParam.ExecuteIfBound();
	Delegate1Param.ExecuteIfBound("Delegate1Param!");
	Delegate5Param.ExecuteIfBound("1Param!", "2Param!", "3Param!", "4Param!", "5Param!");
	FString CurRV = DelegateRV.Execute();
	PrintScreenStr(CurRV);

	 DelegateLambda.ExecuteIfBound("DelegateLambda!");
	 DelegateRaw.ExecuteIfBound("DelegateRaw!");
	 DelegateSP.ExecuteIfBound("DelegateSP!");
	 DelegateStatic.ExecuteIfBound("DelegateStatic!");
	 DelegateUFunction.ExecuteIfBound("DelegateUFunction!");
	
}
void AMyTPCharacter::FuncNoParam()
{
	PrintScreenStr("NoParam");
}
void AMyTPCharacter::Func1Param(FString Str)
{
	PrintScreenStr(Str);
}
void AMyTPCharacter::Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5)
{
	PrintScreenStr(Str1 + " "+ Str2 + " " + Str3 +" "+ Str4 + " " + Str5);
}
FString AMyTPCharacter::FuncRV()
{
	return  FString("FuncRV");
}

void AMyTPCharacter::TestUFunc(FString str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
	}
}





void AMyTPCharacter::OnResetVR()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}



void AMyTPCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void AMyTPCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void AMyTPCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void AMyTPCharacter::MoveRight(float Value)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}

按Q键,运行输出到屏幕如下图:

3、多播代理委托

多播代理的功能和单播代理几乎一样。区别是它们对目标为弱引用,可以和结构体一起使用,可以很方便地进行拷贝,等等。 和普通代理一样,多播代理可被载入/保存,并远程触发;但是,多播代理的函数无法使用返回值。最好将它们用于方便地传递代理集合。事件 是特定类型的多播代理,同时具有对Broadcast(), IsBound(), 和 Clear()函数的受限访问。

多播代理在代理触发时可能会调用多个函数绑定。因此,绑定函数在语句中看起来更为像是数组。

多播代理允许您附加多个函数代理,然后通过调用多播代理的 Broadcast() 函数一次性执行所有函数代理。多播代理的签名不能使用返回值。

任何时候在多播代理上调用 Broadcast() 函数都是安全的,即时它没有绑定任何函数也可以。唯一需要注意的时候是您使用代理初始化输出变量时,这样做一般是非常不好的。

当调用 Broadcast() 函数时,绑定函数的执行顺序是不确定的。可能并不按照函数的添加顺序执行

步骤1和2单播代理委托,指的是只能绑定一个函数指针的委托,实现一对一的通知。
多播代理委托,指的是能绑定多个函数指针的委托,实现一对多的通知。
多播代理委托的定义是有“MULTICAST”修饰的委托

继续基于步骤1、2实现,在编辑器创建基于C++类继承于Actor两个类,名字分别叫做:TestActor、TestActor2

TestActor.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestActor.generated.h"

UCLASS()
class MYTP_API ATestActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ATestActor();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	void FuncNoParam();
	void Func1Param(FString str);

	
};

TestActor.cpp:

// Fill out your copyright notice in the Description page of Project Settings.

#include "TestActor.h"
#include "Engine/GameEngine.h"
#include "MyTPCharacter.h"

// Sets default values
ATestActor::ATestActor()
{
 	// 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;

}

// Called when the game starts or when spawned
void ATestActor::BeginPlay()
{
	Super::BeginPlay();

	APlayerController* PC = GetWorld()->GetFirstPlayerController();
	if (nullptr == PC)
		return;
	ACharacter* Cha = PC->GetCharacter();
	if (nullptr == Cha)
		return;
	AMyTPCharacter* MyTPC = Cast<AMyTPCharacter>(Cha);
	if (nullptr == MyTPC)
		return;

	MyTPC->DelegateMulticastD_NoParam.AddUObject(this, &ATestActor::FuncNoParam);
	MyTPC->DelegateMulticastD_1Param.AddUObject(this, &ATestActor::Func1Param);


}

// Called every frame
void ATestActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void ATestActor::FuncNoParam()
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, "TestActor FuncNoParam");
	}
}
void ATestActor::Func1Param(FString str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, "TestActor Func1Param"+str);
	}
}

TestActor2.h;

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestActor2.generated.h"

UCLASS()
class MYTP_API ATestActor2 : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ATestActor2();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	void FuncNoParam();
	void Func1Param(FString str);

	
};

TestActor2.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "TestActor2.h"
#include "Engine/GameEngine.h"
#include "MyTPCharacter.h"

// Sets default values
ATestActor2::ATestActor2()
{
 	// 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;

}

// Called when the game starts or when spawned
void ATestActor2::BeginPlay()
{
	Super::BeginPlay();

	APlayerController* PC = GetWorld()->GetFirstPlayerController();
	if (nullptr == PC)
		return;
	ACharacter* Cha = PC->GetCharacter();
	if (nullptr == Cha)
		return;
	AMyTPCharacter* MyTPC = Cast<AMyTPCharacter>(Cha);
	if (nullptr == MyTPC)
		return;

	MyTPC->DelegateMulticastD_NoParam.AddUObject(this, &ATestActor2::FuncNoParam);
	MyTPC->DelegateMulticastD_1Param.AddUObject(this, &ATestActor2::Func1Param);

}

// Called every frame
void ATestActor2::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void ATestActor2::FuncNoParam()
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, "TestActor2 FuncNoParam");
	}
}
void ATestActor2::Func1Param(FString str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Yellow, "TestActor2 Func1Param" + str);
	}
}

MyTPCharacter.h:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyTest.h"
#include "MyTPCharacter.generated.h"



//声明无参代理
DECLARE_DELEGATE(D_NoParam)
//声明1个参数的代理
DECLARE_DELEGATE_OneParam(D_1Param, FString)
//声明5个参数的代理
DECLARE_DELEGATE_FiveParams(D_5Param, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, D_RV)

static void Static_Func(FString Str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, Str);
	}
}

//声明多播委托,与单播委托一样支持多参数传入,动态多播代理的名称开头须为F,否则会编译报错
DECLARE_MULTICAST_DELEGATE(FMulticastD_NoParam);//声明无参数多播 
DECLARE_MULTICAST_DELEGATE_OneParam(FMulticastD_1Param, FString);//声明一个参数多播



UCLASS(config=Game)
class AMyTPCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	AMyTPCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;


	//定义代理
	D_NoParam DelegateNoParam;
	D_1Param Delegate1Param;
	D_5Param Delegate5Param;
	D_RV DelegateRV;

	//绑定到代理的函数
	void FuncNoParam();
	void Func1Param(FString Str);
	void Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5);
	FString FuncRV();

	void OnRunEvent();//绑定到Q键函数,执行所有代理
	void PrintScreenStr(FString Str);//打印日志到屏幕函数

	//定义多种绑定
	D_1Param DelegateLambda;
	D_1Param DelegateRaw;
	D_1Param DelegateSP;
	D_1Param DelegateStatic;
	D_1Param DelegateUFunction;

	UFUNCTION()//可以声明BlueprintCallable等其他标记
		void TestUFunc(FString str);
	MyTest MyT;
	TSharedPtr<MyTest> MyT_SPtr;


	//多播
	FMulticastD_NoParam DelegateMulticastD_NoParam;
	FMulticastD_1Param  DelegateMulticastD_1Param;


protected:

	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};

MyTPCharacter.cpp:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "MyTPCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"

#include "Engine/GameEngine.h"
#include "MyTest.h"

//
// AMyTPCharacter

AMyTPCharacter::AMyTPCharacter()
{
	
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)


	DelegateNoParam.BindUObject(this, &AMyTPCharacter::FuncNoParam);//this只能是继承自UObject的类,绑定继承UObject类的对象函数
	Delegate1Param.BindUObject(this, &AMyTPCharacter::Func1Param);
	Delegate5Param.BindUObject(this, &AMyTPCharacter::Func5Param);
	DelegateRV.BindUObject(this, &AMyTPCharacter::FuncRV);


	//Lambda表达式
	auto LambdaFunc = [&](FString str)
	{
		if (GEngine) {
			GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
		}
	};
	DelegateLambda.BindLambda(LambdaFunc);//绑定lambda表达式
	DelegateRaw.BindRaw(&MyT, &MyTest::TestFunc);//绑定到一个原始的C++类函数绑定到一个原始的C++指针全局函数代理上。原始指针不使用任何引用,所以如果从代理的底层删除了该对象,那么调用它可能是不安全的。因此,当调用Execute()时一定要小心!

	
	MyT_SPtr = MakeShareable(new MyTest());
	DelegateSP.BindSP(MyT_SPtr.ToSharedRef(), &MyTest::TestFunc);//绑定一个基于共享指针的成员函数代理。共享指针代理保持到您的对象的弱引用。您可以使用 ExecuteIfBound() 来调用它们。
	DelegateStatic.BindStatic(Static_Func);//绑定全局静态函数
	DelegateUFunction.BindUFunction(this,"TestUFunc");//绑定this指向对象类蓝图函数

}

//
// Input

void AMyTPCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);

	PlayerInputComponent->BindAction("RunEvent", IE_Pressed, this, &AMyTPCharacter::OnRunEvent);



	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &AMyTPCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyTPCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &AMyTPCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &AMyTPCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &AMyTPCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &AMyTPCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AMyTPCharacter::OnResetVR);

	
}


void AMyTPCharacter::PrintScreenStr(FString Str)
{
	if (GEngine) 
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Red, Str);
	}
}

void AMyTPCharacter::OnRunEvent()
{
	//执行单播
	DelegateNoParam.ExecuteIfBound();
	Delegate1Param.ExecuteIfBound("Delegate1Param!");
	Delegate5Param.ExecuteIfBound("1Param!", "2Param!", "3Param!", "4Param!", "5Param!");
	FString CurRV = DelegateRV.Execute();
	PrintScreenStr(CurRV);

	 DelegateLambda.ExecuteIfBound("DelegateLambda!");
	 DelegateRaw.ExecuteIfBound("DelegateRaw!");
	 DelegateSP.ExecuteIfBound("DelegateSP!");
	 DelegateStatic.ExecuteIfBound("DelegateStatic!");
	 DelegateUFunction.ExecuteIfBound("DelegateUFunction!");

	 //执行多播
	 DelegateMulticastD_NoParam.Broadcast();
	 DelegateMulticastD_1Param.Broadcast(FString("@1Param!!!"));
	
}
void AMyTPCharacter::FuncNoParam()
{
	PrintScreenStr("NoParam");
}
void AMyTPCharacter::Func1Param(FString Str)
{
	PrintScreenStr(Str);
}
void AMyTPCharacter::Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5)
{
	PrintScreenStr(Str1 + " "+ Str2 + " " + Str3 +" "+ Str4 + " " + Str5);
}
FString AMyTPCharacter::FuncRV()
{
	return  FString("FuncRV");
}

void AMyTPCharacter::TestUFunc(FString str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
	}
}





void AMyTPCharacter::OnResetVR()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}



void AMyTPCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void AMyTPCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void AMyTPCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void AMyTPCharacter::MoveRight(float Value)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}

编辑器分别创建继承于TestActor、TestActor2的蓝图类TestA、TestA2,并且把它们摆放到测试场景关卡生成;

启动游戏后,摁Q键,运行效果如下:

 

4、动态多播代理委托(与蓝图混合使用)

动态委托可以序列化,它们的函数可以通过名称找到,而且它们比常规委托慢。动态代理的使用方法和普通代理相似,不过动态多播代理可以暴露给蓝图绑定,方便在蓝图做处理,特别是C++和UMG数据通知交互。

还是基于步骤1/2/3来实现,代码过程如下:

MyTPCharacter.h:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyTest.h"
#include "MyTPCharacter.generated.h"



//声明无参代理
DECLARE_DELEGATE(D_NoParam)
//声明1个参数的代理
DECLARE_DELEGATE_OneParam(D_1Param, FString)
//声明5个参数的代理
DECLARE_DELEGATE_FiveParams(D_5Param, FString, FString, FString, FString, FString)
//返回值代理
DECLARE_DELEGATE_RetVal(FString, D_RV)

static void Static_Func(FString Str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, Str);
	}
}

//声明多播委托,与单播委托一样支持多参数传入,动态多播代理的名称开头须为F,否则会编译报错
DECLARE_MULTICAST_DELEGATE(FMulticastD_NoParam);//声明无参数多播 
DECLARE_MULTICAST_DELEGATE_OneParam(FMulticastD_1Param, FString);//声明一个参数多播

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDynamicMulticastD_1Param, FString, Str);//声明一个参数动态多播,动态多播代理的名称开头须为F,否则会编译报错

UCLASS(config=Game)
class AMyTPCharacter : public ACharacter
{
	GENERATED_BODY()

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;
public:
	AMyTPCharacter();

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
	float BaseLookUpRate;


	//定义代理
	D_NoParam DelegateNoParam;
	D_1Param Delegate1Param;
	D_5Param Delegate5Param;
	D_RV DelegateRV;

	//绑定到代理的函数
	void FuncNoParam();
	void Func1Param(FString Str);
	void Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5);
	FString FuncRV();

	void OnRunEvent();//绑定到Q键函数,执行所有代理
	void PrintScreenStr(FString Str);//打印日志到屏幕函数

	//定义多种绑定
	D_1Param DelegateLambda;
	D_1Param DelegateRaw;
	D_1Param DelegateSP;
	D_1Param DelegateStatic;
	D_1Param DelegateUFunction;

	UFUNCTION()//可以声明BlueprintCallable等其他标记
		void TestUFunc(FString str);
	MyTest MyT;
	TSharedPtr<MyTest> MyT_SPtr;


	//多播
	FMulticastD_NoParam DelegateMulticastD_NoParam;
	FMulticastD_1Param  DelegateMulticastD_1Param;

	UPROPERTY(BlueprintAssignable)//可在蓝图上绑定分配
	FDynamicMulticastD_1Param  DelegateDynamicMulticastD_1Param;//动态多播

protected:

	/** Resets HMD orientation in VR. */
	void OnResetVR();

	/** Called for forwards/backward input */
	void MoveForward(float Value);

	/** Called for side to side input */
	void MoveRight(float Value);

	/** 
	 * Called via input to turn at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void TurnAtRate(float Rate);

	/**
	 * Called via input to turn look up/down at a given rate. 
	 * @param Rate	This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
	 */
	void LookUpAtRate(float Rate);

	/** Handler for when a touch input begins. */
	void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);

	/** Handler for when a touch input stops. */
	void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	// End of APawn interface

public:
	/** Returns CameraBoom subobject **/
	FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
	/** Returns FollowCamera subobject **/
	FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};

MyTPCharacter.cpp:

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "MyTPCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"

#include "Engine/GameEngine.h"
#include "MyTest.h"

//
// AMyTPCharacter

AMyTPCharacter::AMyTPCharacter()
{
	
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// set our turn rates for input
	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)


	DelegateNoParam.BindUObject(this, &AMyTPCharacter::FuncNoParam);//this只能是继承自UObject的类,绑定继承UObject类的对象函数
	Delegate1Param.BindUObject(this, &AMyTPCharacter::Func1Param);
	Delegate5Param.BindUObject(this, &AMyTPCharacter::Func5Param);
	DelegateRV.BindUObject(this, &AMyTPCharacter::FuncRV);


	//Lambda表达式
	auto LambdaFunc = [&](FString str)
	{
		if (GEngine) {
			GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
		}
	};
	DelegateLambda.BindLambda(LambdaFunc);//绑定lambda表达式
	DelegateRaw.BindRaw(&MyT, &MyTest::TestFunc);//绑定到一个原始的C++类函数绑定到一个原始的C++指针全局函数代理上。原始指针不使用任何引用,所以如果从代理的底层删除了该对象,那么调用它可能是不安全的。因此,当调用Execute()时一定要小心!

	
	MyT_SPtr = MakeShareable(new MyTest());
	DelegateSP.BindSP(MyT_SPtr.ToSharedRef(), &MyTest::TestFunc);//绑定一个基于共享指针的成员函数代理。共享指针代理保持到您的对象的弱引用。您可以使用 ExecuteIfBound() 来调用它们。
	DelegateStatic.BindStatic(Static_Func);//绑定全局静态函数
	DelegateUFunction.BindUFunction(this,"TestUFunc");//绑定this指向对象类蓝图函数

}

//
// Input

void AMyTPCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up gameplay key bindings
	check(PlayerInputComponent);

	PlayerInputComponent->BindAction("RunEvent", IE_Pressed, this, &AMyTPCharacter::OnRunEvent);



	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveForward", this, &AMyTPCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AMyTPCharacter::MoveRight);

	// We have 2 versions of the rotation bindings to handle different kinds of devices differently
	// "turn" handles devices that provide an absolute delta, such as a mouse.
	// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
	PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis("TurnRate", this, &AMyTPCharacter::TurnAtRate);
	PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("LookUpRate", this, &AMyTPCharacter::LookUpAtRate);

	// handle touch devices
	PlayerInputComponent->BindTouch(IE_Pressed, this, &AMyTPCharacter::TouchStarted);
	PlayerInputComponent->BindTouch(IE_Released, this, &AMyTPCharacter::TouchStopped);

	// VR headset functionality
	PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AMyTPCharacter::OnResetVR);

	
}


void AMyTPCharacter::PrintScreenStr(FString Str)
{
	if (GEngine) 
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Red, Str);
	}
}

void AMyTPCharacter::OnRunEvent()
{
	//执行单播
	DelegateNoParam.ExecuteIfBound();
	Delegate1Param.ExecuteIfBound("Delegate1Param!");
	Delegate5Param.ExecuteIfBound("1Param!", "2Param!", "3Param!", "4Param!", "5Param!");
	FString CurRV = DelegateRV.Execute();
	PrintScreenStr(CurRV);

	 DelegateLambda.ExecuteIfBound("DelegateLambda!");
	 DelegateRaw.ExecuteIfBound("DelegateRaw!");
	 DelegateSP.ExecuteIfBound("DelegateSP!");
	 DelegateStatic.ExecuteIfBound("DelegateStatic!");
	 DelegateUFunction.ExecuteIfBound("DelegateUFunction!");

	 //执行多播
	 DelegateMulticastD_NoParam.Broadcast();
	 DelegateMulticastD_1Param.Broadcast(FString("@1Param!!!"));
	 DelegateDynamicMulticastD_1Param.Broadcast(FString("@1DynamicMulticast!"));//执行动态多播
}
void AMyTPCharacter::FuncNoParam()
{
	PrintScreenStr("NoParam");
}
void AMyTPCharacter::Func1Param(FString Str)
{
	PrintScreenStr(Str);
}
void AMyTPCharacter::Func5Param(FString Str1, FString Str2, FString Str3, FString Str4, FString Str5)
{
	PrintScreenStr(Str1 + " "+ Str2 + " " + Str3 +" "+ Str4 + " " + Str5);
}
FString AMyTPCharacter::FuncRV()
{
	return  FString("FuncRV");
}

void AMyTPCharacter::TestUFunc(FString str)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, str);
	}
}





void AMyTPCharacter::OnResetVR()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}



void AMyTPCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
		Jump();
}

void AMyTPCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
		StopJumping();
}

void AMyTPCharacter::TurnAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::LookUpAtRate(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void AMyTPCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void AMyTPCharacter::MoveRight(float Value)
{
	if ( (Controller != NULL) && (Value != 0.0f) )
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
	
		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}

UPROPERTY(BlueprintAssignable)//可在蓝图上绑定分配
    FDynamicMulticastD_1Param  DelegateDynamicMulticastD_1Param;//动态多播

定义多播DelegateDynamicMulticastD_1Param在蓝图TestA、TestA1、ThirdPersonCharacter蓝图上绑定,如下图

运行游戏,摁下Q键,运行效果如下:

 

5、代理委托解绑

UnBind():解除绑定该代理。

Remove():
将函数从这个多播代理的调用列表中移除(性能为O(N))。请注意代理的顺序可能不会被保留!


RemoveAll():
将所有函数从与特定UserObject绑定的多播代理的调用列表中移除。请注意代理的顺序可能不会被保留!
RemoveAll()将会移除所有与提供的指针绑定的注册代理! 不与对象指针绑定的原始代理将不会被此函数移除!
 

注意:代理委托绑定时候,绑定函数返回一个代理委托,可以在绑定注册代理委托对象类的EndPlay、Destroyed等结束函数解绑该代理委托。

 

完毕!解释都在代码里看到,代理委托有点像软件设计模式中的“观察者模式(Observer)”的具体运用,类与类可以降低低耦合!

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值