参考文章:
Delegate(委托)
UE4 C++进阶进行中 
UE4代理上
一文理解透UE委托Delegate
UE官方文档
委托简介
委托本质上是一个函数指针的封装,它可以绑定一个函数,之后在某个时刻调用这个函数。
主要作用是将实时监测的逻辑转换为触发式逻辑,同时降低代码之间的耦合性
常用的委托有单播、多播、动态多播和事件等;
上述委托的概念不在赘述,详细请参考UE官方文档和一文理解透UE委托Delegate以及上面提及的视频连接
委托的使用
由于每种委托的使用方法几乎一样,在此只使用单播作为介绍委托的使用。
委托使用的原理
下图是委托的整个事件类型

下图是使用委托的三个基本类

从上图可以看到,使用委托和不使用委托的区别,使用委托可以降低事件触发类和被调用类之间的耦合,将这两个类的操作放在委托制造类里面进行操作,这对于大型项目十分重要。
这里做个比喻就是:你点了一家饭店的吃饭,你要吃的饭汇报给饭店,饭店指定厨师做饭并将饭端给你。这里的你就是事件触发类,饭店就是委托制造类,厨师就是被调用类。
代码实现
这里的代码修改了 UEC++实现人物按照A星路线移动 里面的算法,有需要可以去参考
事件触发类
AStar_test2Character.h
| 12
 
 | UMyDelegateMaker* Maker;
 
 | 
AStar_test2Character.cpp
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | void AAStar_test2Character::SpineSet(){
 UWorld* World = GetWorld();
 if (Maker == nullptr)
 {
 Maker = NewObject<UMyDelegateMaker>();
 }
 
 Maker->BindSpineSet(World).Execute();
 
 }
 
 void AAStar_test2Character::AIMove()
 {
 UE_LOG(LogTemp, Warning, TEXT("按下3,开始执行AIMOVE"));
 UWorld* World = GetWorld();
 if (!World) return;
 
 if (Maker == nullptr)
 {
 Maker = NewObject<UMyDelegateMaker>();
 }
 
 Maker->BindAIMove(World).Execute();
 }
 
 | 
委托制造类(重点)
MyDelegateMaker.h
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | 
 #pragma once
 
 #include "CoreMinimal.h"
 #include "UObject/NoExportTypes.h"
 #include "MyDelegateMaker.generated.h"
 
 
 DECLARE_DELEGATE(FDelegateNoParam)
 
 
 
 UCLASS()
 class ASTAR_TEST2_API UMyDelegateMaker : public UObject
 {
 GENERATED_BODY()
 
 public:
 
 FDelegateNoParam Delegate;
 FDelegateNoParam Delegate_AIMove;
 
 
 
 
 FDelegateNoParam& BindSpineSet(UWorld*  World);
 
 FDelegateNoParam& BindAIMove(UWorld*  World);
 
 class ASpine* USpineRef = nullptr;
 
 class AMyAIController* AIControllerRef = nullptr;
 
 };
 
 | 
MyDelegateMaker.cpp
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 
 | #include "MyDelegateMaker.h"
 #include "EngineUtils.h"
 #include "MyAIController.h"
 #include "Spine.h"
 #include "Kismet/GameplayStatics.h"
 
 FDelegateNoParam& UMyDelegateMaker::BindSpineSet(UWorld*  World)
 {
 
 if (Delegate.IsBound())
 {
 Delegate.Unbind();
 }
 
 
 if (USpineRef == nullptr)
 {
 if(World == nullptr)  {
 UE_LOG(LogTemp, Error, TEXT("World is nullptr"));
 }
 else
 {
 for (TActorIterator<ASpine> It(World); It; ++It)
 {
 USpineRef = *It;
 
 }
 }
 
 }
 
 Delegate.BindUObject(USpineRef, &ASpine::setSpine);
 
 return Delegate;
 }
 
 FDelegateNoParam& UMyDelegateMaker::BindAIMove(UWorld* World)
 {
 if (Delegate.IsBound())
 {
 Delegate.Unbind();
 }
 
 if (AIControllerRef == nullptr)
 {
 if (World)
 {
 for (TActorIterator<AMyAIController> It(World); It; ++It)
 {
 AIControllerRef = *It;
 }
 Delegate_AIMove.BindUObject(AIControllerRef, &AMyAIController::goAIMove);
 }
 }
 
 return Delegate_AIMove;
 }
 
 
 | 
被调用类
该类中的方法主要是依据A星路线动态生成样条点,可以掠过不看,注意使用方法即可
Spine.h
| 12
 3
 
 | UFUNCTION()
 void setSpine() const;
 
 | 
Spine.cpp
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | void ASpine::setSpine() const
 {
 UWorld* World = GetWorld();
 
 
 USplineComponent* SplineComp = this -> FindComponentByClass<USplineComponent>();
 if (!SplineComp) return;
 
 
 APlayerController* PlayerController = UGameplayStatics::GetPlayerController(World, 0);
 if (!PlayerController) return;
 AAStar_test2Character* Character = Cast<AAStar_test2Character>(PlayerController->GetPawn());
 if (!Character) return;
 TArray<FVector> Vectors = Character->AllPositions;
 
 
 for (const FVector& Position : Vectors)
 {
 SplineComp->AddSplinePoint(Position, ESplineCoordinateSpace::World);
 }
 
 
 SplineComp->UpdateSpline();
 
 }
 
 |