基於C++程式碼的UE4學習(五)—— 帶一個引數的FParamDelegateSignature動態代理與函式指標
之前我們使用FStandardDeltegateSignature類進行了無引數的函式繫結,也有人告訴我說叫做觀察者模式。
今天我們先使用函式指標完成FStandardDeltegateSignature類的功能。
以下是繼承自Actor類的PointLightListner類的標頭檔案程式碼:
1 #pragma once 2 3 #include "CoreMinimal.h" 4 #include "GameFramework/Actor.h" 5 #include "Components\PointLightComponent.h" 6 #include "PointLightListner.generated.h" 7 8 UCLASS() 9 class MYPROJECT6_API APointLightListner : public AActor 10 { 11 GENERATED_BODY() 12 13 public: 14 // Sets default values for this actor's properties 15 APointLightListner(); 16 17 protected: 18 // Called when the game starts or when spawned 19 virtual voidBeginPlay() override; 20 21 virtual void EndPlay(EEndPlayReason::Type EndReason) override; 22 23 public: 24 // Called every frame 25 virtual void Tick(float DeltaTime) override; 26 27 28 29 public: 30 31 UPROPERTY() 32 class UPointLightComponent* pointLight; 33 34 UFUNCTION()35 void enableLight(); 36 37 UFUNCTION() 38 void closeLight(); 39 40 UFUNCTION() 41 void SelfLight(FLinearColor color); 42 };
以下是繼承自Actor類的PointLightListner類的原始檔程式碼:
其中註釋起來的程式碼是之前用作FStandardDelegateSignature類內容設計的,這裡可以暫時忽略。
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 4 #include "PointLightListner.h" 5 #include "Kismet/GameplayStatics.h" 6 #include "MyProject6GameModeBase.h" 7 8 // Sets default values 9 APointLightListner::APointLightListner() 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 pointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("pointLight")); 14 pointLight->SetVisibility(true); 15 pointLight->SetLightColor(FLinearColor::Blue); 16 } 17 18 // Called when the game starts or when spawned 19 void APointLightListner::BeginPlay() 20 { 21 Super::BeginPlay(); 22 /* 23 auto ParentGameMode = UGameplayStatics::GetGameMode(GetWorld()); 24 25 AMyProject6GameModeBase* myGameModeBase = Cast<AMyProject6GameModeBase>(ParentGameMode); 26 27 if (myGameModeBase) { 28 //myGameModeBase->myDelegate1.BindUObject(this,&APointLightListner::enableLight); 29 myGameModeBase->myDelegate2.BindUObject(this, &APointLightListner::closeLight); 30 myGameModeBase->myOneParamDelegate.BindUObject(this, &APointLightListner::SelfLight); 31 } 32 */ 33 34 } 35 36 void APointLightListner::EndPlay(EEndPlayReason::Type EndReason) 37 { 38 39 Super::EndPlay(EndReason); 40 /* 41 auto ParentGameMode = UGameplayStatics::GetGameMode(GetWorld()); 42 43 AMyProject6GameModeBase* myGameModeBase = Cast<AMyProject6GameModeBase>(ParentGameMode); 44 45 if (myGameModeBase) { 46 //myGameModeBase->myDelegate1.Unbind(); 47 myGameModeBase->myDelegate2.Unbind(); 48 myGameModeBase->myOneParamDelegate.Unbind(); 49 } 50 */ 51 52 } 53 54 // Called every frame 55 void APointLightListner::Tick(float DeltaTime) 56 { 57 Super::Tick(DeltaTime); 58 59 } 60 61 62 void APointLightListner::enableLight() { 63 pointLight->SetLightColor(FLinearColor::Red); 64 } 65 66 67 void APointLightListner::closeLight() { 68 pointLight->SetLightColor(FLinearColor::Blue); 69 } 70 71 void APointLightListner::SelfLight(FLinearColor color) 72 { 73 pointLight->SetLightColor(color); 74 }
實現方是一個燈元件及其開關的方法及顏色。現在要實現觸發方。
以下是繼承自Actor類的TriggerS類的標頭檔案程式碼:
它匯入了PointLightListner類的標頭檔案,因為要訪問它類中的方法。
再建立一個Box的碰撞體。
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 "PointLightListner.h" 8 #include "Components\BoxComponent.h" 9 #include "TriggerS.generated.h" 10 11 12 UCLASS() 13 class MYPROJECT6_API ATriggerS : public AActor 14 { 15 GENERATED_BODY() 16 17 public: 18 // Sets default values for this actor's properties 19 ATriggerS(); 20 21 protected: 22 // Called when the game starts or when spawned 23 virtual void BeginPlay() override; 24 25 public: 26 // Called every frame 27 virtual void Tick(float DeltaTime) override; 28 29 public: 30 UFUNCTION(BlueprintCallable) 31 virtual void NotifyActorBeginOverlap(AActor* actor) override; 32 33 UFUNCTION(BlueprintCallable) 34 virtual void NotifyActorEndOverlap(AActor* actor) override; 35 UPROPERTY() 36 class UBoxComponent* box; 37 38 };
1 // Fill out your copyright notice in the Description page of Project Settings. 2 3 4 #include "TriggerS.h" 5 #include "Kismet/GameplayStatics.h" 6 7 // Sets default values 8 ATriggerS::ATriggerS() 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 box = CreateDefaultSubobject<UBoxComponent>(TEXT("box")); 13 RootComponent = box; 14 box->InitBoxExtent(FVector(80.0f)); 15 } 16 17 // Called when the game starts or when spawned 18 void ATriggerS::BeginPlay() 19 { 20 Super::BeginPlay(); 21 22 } 23 24 // Called every frame 25 void ATriggerS::Tick(float DeltaTime) 26 { 27 Super::Tick(DeltaTime); 28 29 } 30 31 void ATriggerS::NotifyActorBeginOverlap(AActor* actor) 32 { 33 void (APointLightListner:: * PL)(); 34 PL = &APointLightListner::enableLight; 35 36 37 TArray<AActor*> alist; 38 39 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), alist); 40 41 for (int i = 0; i < alist.Num(); i++) { 42 APointLightListner * pll= Cast<APointLightListner>(alist[i]); 43 if (pll) { 44 (pll->*PL)(); 45 } 46 } 47 } 48 49 void ATriggerS::NotifyActorEndOverlap(AActor* actor) 50 { 51 52 void (APointLightListner:: * PL)(); 53 PL = &APointLightListner::closeLight; 54 55 56 TArray<AActor*> alist; 57 58 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), alist); 59 60 for (int i = 0; i < alist.Num(); i++) { 61 APointLightListner* pll = Cast<APointLightListner>(alist[i]); 62 if (pll) { 63 (pll->*PL)(); 64 } 65 } 66 }
在NotifyActorBeginOverlap和NotifyActorEndOverlap方法中建立陣列和PointLightListner類的函式指標,指向類中的方法。
效果如下,可以達到同樣效果。
接下來看帶有一個引數的FParamDelegateSignature類代理,其使用方法與FStandardDelegateSignature類幾乎完全一樣,除了兩個地方,在宣告階段是這樣的。
1 DECLARE_DELEGATE_OneParam(FParamDelegateSignature,FLinearColor)
宣告帶引數的代理,用DECLARE_DELEGATE_OneParam()巨集定義,我試了下,可以一直寫到DECLARE_DELEGATE_NineParam(),意思就是可以繫結帶有9個引數的方法。
巨集定義的第一個引數中傳入代理型別,這裡就是FParamDelegateSignature類,第二個引數是要繫結的方法需要傳入的資料型別,這裡需要傳入的是一個FLinearColor型別。
第二個地方不同的是,在FStandardDelegateSignature類物件將類中的繫結好的方法進行執行的時候,用到的是ExcuteIfBound方法,而FParamDelegateSignature類物件執行繫結好的方法的時候,使用的是Excute方法。
FParamDelegateSignature類其他例如繫結方法,解綁方法,與FStandardDelegateSignature類都是相同的。
BindUObject()
Unbind();