UE5--浅析委托原理(Delegate)

发布于:2025-02-11 ⋅ 阅读:(11) ⋅ 点赞:(0)

委托概述

委托是一种用于事件处理的机制。通过使用委托,可以将一个或多个函数绑定到一个事件上,在事件触发时自动调用这些函数。代理也叫做委托,比如:跳,跑,开枪,伤害等响应,就是注册一个委托回调,其作用就是提供一种消息机制,都知道消息的传递需要发送方和接收方,而代理的过程也可分为这两大部分,我们可以换个名字分别叫做:触发点和执行点,这就是代理的主要部分,记住这个两个点就能记住代理原理。这里面也有很多的类型擦除,类型还原,还有函数签名转换。

委托种类

在这里插入图片描述

委托的使用

三个步骤:

1.声明委托代理

2.绑定函数到代理上

3.代理的调用

单播

DECLARE_DELEGATE( FSimpleDelegate ); // 无参、无返回值
DECLARE_DELEGATE_OneParam(FPakEncryptionKeyDelegate, uint8[32]); // 1个参数、无返回值
DECLARE_DELEGATE_TwoParams(FPakSigningKeysDelegate, TArray<uint8>&, TArray<uint8>&); // 2个参数、无返回值
DECLARE_DELEGATE_RetVal_ThreeParams(bool, FOnMountPak, const FString&, int32, IPlatformFile::FDirectoryVisitor*); // 3个参数、bool返回

声明定义单播可以有参数和无参数

单播代理委托,指的是只能绑定一个函数指针的委托,实现一对一的通知。

单播调用方式为 ExecuteIfBound()

单播删除方式为 Unbind()

单播绑定方法为 Bind…(如 BindStatic,BindRaw,BindUObject等)

多播

//多播委托
DECLARE_MULTICAST_DELEGATE(DelegateName);
DECLARE_MULTICAST_DELEGATE_ONEPARAM(DelegateName, Param1Type);
DECLARE_MULTICAST_DELEGATE_XXXPARAMS(DelegateName, Param1Type,...);

多播代理委托,指的是能绑定多个函数指针的委托,实现一对多的通知。

多播调用方式为 BroadCast()

多播的删除方式为 Remove(),RemoveAll()

多播绑定方式为 Add…(如 AddUObject…);

注意

1.只要动态多播才可以被蓝图绑定,通过宏定义BlueprintAsignable

2.看是否有返回值,通过关键字“RetVal”,只有单播委托和动态单播委托,才有返回值。

3.多播委托和单播委托都支持多参数传入,最多9个参数

4.委托的开头必须用F,否则无法编译

5.动态委托可以序列化,通过名称查找函数。

动态委托案例

下面是我用来学习动态委托的一个小案例,让自己更清楚的看见委托的使用与过程

新建两个C++对象
在这里插入图片描述
然后拖入场景,一下是两个Actor的代码

MyActorA

.h

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

#pragma once

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

/*
* 让A进行对B的调用,我们就需要在A中声明委托类型
* 我们这里测试动态多播参数
* 必须使用F开头的
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDongTaiDuoBo,bool,OkorNotOk);


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

	UPROPERTY(BlueprintAssignable)
	FDongTaiDuoBo DongTaiDuoBo;

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

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

	//用来执行触发委托
	UFUNCTION(BlueprintCallable)
	void execute(bool ifSuccess);

};

.cpp

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


#include "MyActorA.h"

// Sets default values
AMyActorA::AMyActorA()
{
 	// 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 AMyActorA::BeginPlay()
{
	Super::BeginPlay();
	
}

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

}

void AMyActorA::execute(bool ifSuccess)
{
    //这里用来触发委托
    DongTaiDuoBo.Broadcast(ifSuccess);
}

MyActorB

.h

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

#pragma once

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

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

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

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

	/*
	* 这里来调用A里面的委托
	* 现在写一个被委托的函数
	*/

	UFUNCTION(BlueprintCallable)
	void Bexecute(bool ifSuccess);
};

.cpp

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


#include "MyActorB.h"
#include "MyActorA.h"
#include "Kismet\GameplayStatics.h"
// Sets default values
AMyActorB::AMyActorB()
{
 	// 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 AMyActorB::BeginPlay()
{
	Super::BeginPlay();

	/*
	* 在场景中寻找A
	*/
	TArray<AActor*>Actors;
	
	UGameplayStatics::GetAllActorsOfClass(GetWorld(),AMyActorA::StaticClass(),Actors);
	//在场景中遍历到我我们需要的ActorB,然后把函数绑定到ActorB上面
	for (auto Actor : Actors)
	{
	    AMyActorA* A=Cast<AMyActorA>(Actor);
		if (A!=nullptr)
		{
		    //把找到的AActor转换成A需要的类
		    A->DongTaiDuoBo.AddDynamic(this,&AMyActorB::Bexecute);
		}
	}
}

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

}

void AMyActorB::Bexecute(bool ifSuccess)
{
    if (ifSuccess)
    {
	    UE_LOG(LogTemp,Warning,TEXT("Success"));
    }
	else 
	{
		UE_LOG(LogTemp, Warning, TEXT("NotSuccessnnnnnn"));
	}

}

在关卡蓝图中,进行连连看
在这里插入图片描述
MyActorA
在这里插入图片描述
测试结果
在这里插入图片描述
之后你就会发现我们的动态委托测试成功了。