动态代理类是FScriptDelegate,用来函数绑定的,例如当角色触碰到碰撞体之后,拥有该碰撞体的ACTOR运行某个函数。
例如
1 FScriptDelegate start; 2 3 start.BindUFunction(this,"onOverlap"); 4 5 6 myCollision->OnComponentBeginOverlap.Add(start); 7 8 9 void AMyActor::onOverlap(){ 10 11 UE_LOG(LogTemp,Warning,TEXT("GOOD")); 12 13 }
标准代理:
标准代理的实现是通过FStandardDelegateSignature类实现的,且涉及到三方,一为触发方,一为实现方,一为绑定方。
FStandardDelegateSignature类就是充当绑定方,它负责将触发方和实现方链接起来,并传输信号,触发时候,实现方改如何反应。这一过程也可以跳过FStandardDelegateSignature类实现,但是并不建议这么做,因为涉及指针安全问题。
例如我们需要走到一个碰撞体上将一个灯打开,碰撞体就是触发方,灯就是实现方。
我们先建立标准代理方,这里选用公共的类,GAMEMODE类作为标准代理方的载体。
1 DECLARE_DELEGATE(FStandardDelegateSignature)
这句宏定义需要放在UCLASS()宏定义之前。
1 // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/GameModeBase.h" 7 #include "StandardDelegateGameModeBase.generated.h" 8 9 10 11 DECLARE_DELEGATE(FStandardDelegateSignature) 12 13 UCLASS() 14 class STANDARDDELEGATE_API AStandardDelegateGameModeBase : public AGameModeBase 15 { 16 GENERATED_BODY() 17 public: 18 FStandardDelegateSignature myStandardDelegate; //标准代理类的对象 myStandardDelegate
FStandardDelegateSignature myStandardDelegate2;
};
标准代理需要与实现方的开灯和关灯函数进行绑定:
实现方的头文件:
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/Actor.h" 7 #include "StandardDelegateGameModeBase.h" 8 #include "Components\PointLightComponent.h" 9 #include "MyActorListener.generated.h" 10 11 UCLASS() 12 class STANDARDDELEGATE_API AMyActorListener : public AActor 13 { 14 GENERATED_BODY() 15 16 public: 17 // Sets default values for this actor's properties 18 AMyActorListener(); 19 20 protected: 21 // Called when the game starts or when spawned 22 virtual void BeginPlay() override; 23 24 public: 25 // Called every frame 26 virtual void Tick(float DeltaTime) override; 27 28 public: 29 UFUNCTION() 30 void enableLight(); 31 32 UFUNCTION() 33 void closeLight(); 34 35 UPROPERTY(VisibleAnywhere,BlueprintReadWrite) 36 class UPointLightComponent* pointLight; 37 };
实现方的源文件:
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 4 #include "MyActorListener.h" 5 #include "Kismet\GameplayStatics.h" 6 7 // Sets default values 8 AMyActorListener::AMyActorListener() 9 { 10 // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 11 PrimaryActorTick.bCanEverTick = true; 12 pointLight = CreateDefaultSubobject(TEXT("pointLight")); 13 RootComponent = pointLight; 14 pointLight->SetVisibility(false); 15 pointLight->SetLightColor(FLinearColor(0,1,0,1)); 16 } 17 18 // Called when the game starts or when spawned 19 void AMyActorListener::BeginPlay() 20 { 21 Super::BeginPlay(); 22 23 UWorld* world = GetWorld(); 24 AGameModeBase* modeBase = UGameplayStatics::GetGameMode(world); 25 26 AStandardDelegateGameModeBase* myGameMode = Cast < AStandardDelegateGameModeBase>(modeBase); 27 28 if (myGameMode) { 29 myGameMode->myStandardDelegate.BindUObject(this,&AMyActorListener::enableLight); 30 myGameMode->myStandardDelegate2.BindUObject(this,&AMyActorListener::closeLight); 31 } 32 } 33 34 // Called every frame 35 void AMyActorListener::Tick(float DeltaTime) 36 { 37 Super::Tick(DeltaTime); 38 39 } 40 41 void AMyActorListener::enableLight() 42 { 43 pointLight->SetVisibility(true); 44 pointLight->SetLightColor(FLinearColor::Red); 45 } 46 47 48 void AMyActorListener::closeLight() 49 { 50 pointLight->SetVisibility(false); 51 }
myGameMode->myStandardDelegate.BindUObject(this,&AMyActorListener::enableLight); myGameMode->myStandardDelegate2.BindUObject(this,&AMyActorListener::closeLight);
这两句代码通过GAMEMODE中的标准代理类的对象对实现方中要实现的开关灯的函数进行了帮绑定。
绑定过后并没有完成全部工作,还需要一个触发方,当满足触发条件时候,这个标准代理类将执行它已经绑定好的函数。
触发方的头文件:
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 #pragma once 4 5 #include "CoreMinimal.h" 6 #include "GameFramework/Actor.h" 7 #include "Components\BoxComponent.h" 8 #include "TriggerActor.generated.h" 9 10 UCLASS() 11 class STANDARDDELEGATE_API ATriggerActor : public AActor 12 { 13 GENERATED_BODY() 14 15 public: 16 // Sets default values for this actor's properties 17 ATriggerActor(); 18 19 protected: 20 // Called when the game starts or when spawned 21 virtual void BeginPlay() override; 22 23 public: 24 // Called every frame 25 virtual void Tick(float DeltaTime) override; 26 27 public: 28 UPROPERTY() 29 class UBoxComponent* box; 30 31 UFUNCTION() 32 virtual void NotifyActorBeginOverlap(AActor* OtherActor) override; 33 34 UFUNCTION() 35 virtual void NotifyActorEndOverlap(AActor* OtherActor) override; 36 };
触发方加载了BOX碰撞体,所以也拥有了NotifyActorBeginOverlap和NotifyActorEndOverlap两个方法,分别是开始重叠和结束重叠时该做什么的函数。我们将在这两个函数里执行标准代理对象绑定好的开关等函数。
触发方的源文件:
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 4 #include "TriggerActor.h" 5 #include "Kismet\GameplayStatics.h" 6 #include "StandardDelegateGameModeBase.h" 7 8 // Sets default values 9 ATriggerActor::ATriggerActor() 10 { 11 // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 12 PrimaryActorTick.bCanEverTick = true; 13 box = CreateDefaultSubobject(TEXT("box")); 14 box->InitBoxExtent(FVector(50.0f)); 15 } 16 17 // Called when the game starts or when spawned 18 void ATriggerActor::BeginPlay() 19 { 20 Super::BeginPlay(); 21 22 } 23 24 // Called every frame 25 void ATriggerActor::Tick(float DeltaTime) 26 { 27 Super::Tick(DeltaTime); 28 29 } 30 31 void ATriggerActor::NotifyActorBeginOverlap(AActor* OtherActor) 32 { 33 AGameModeBase *fatherGameModeBase = UGameplayStatics::GetGameMode(GetWorld()); 34 AStandardDelegateGameModeBase* myModeBase = Cast (fatherGameModeBase); 35 36 37 if (myModeBase) { 38 myModeBase->myStandardDelegate.ExecuteIfBound(); 39 } 40 41 42 } 43 44 void ATriggerActor::NotifyActorEndOverlap(AActor* OtherActor) 45 { 46 AGameModeBase* fatherGameModeBase = UGameplayStatics::GetGameMode(GetWorld()); 47 AStandardDelegateGameModeBase* myModeBase = Cast (fatherGameModeBase); 48 49 50 if (myModeBase) { 51 myModeBase->myStandardDelegate2.ExecuteIfBound(); 52 } 53 54 }
通过以下代码来执行标准代理类对象绑定好的函数
1 myModeBase->myStandardDelegate2.ExecuteIfBound();
需要注意的是FStandardDelegateSignature类只能绑定无参数的函数。
以下是效果实现图,当触发碰撞体的时候,开灯,且灯为红色,离开碰撞体的时候,灯关闭。
目前用到的UGameplayStatics类中的方法有:
UGameplayStatics::GetGameMode(GetWorld());
UGameplayStatics::GetAllActorsOfClass(GetWorld(),AActors::StaticClass(),TArrayactorlist);
UGameplayStatics::GetPlayerController(this,0);
UGameplayStatics::GetAllActorsWithTag(GetWorld(),TEXT("TAGNAME"),TArrayactorlist);