[UE4]事件處理(Handling Events)和委託(Delegate)代碼示例(二)【C++】

3. 建立帶參數的委託

咱們能夠經過修改委託的簽名來使其接受參數ide

好比咱們須要接受一個參數的話,能夠在 GameMode 中這樣聲明:函數

DECLARE_DELEGATE_OneParam(FParamDelegateSignature, FLinearColor)

注意:這個宏與以前稍有不一樣,後綴多出了一個 _OneParam ,並且咱們還須要指定接受參數的類型——本例爲 FLinearColorthis

接着再添加一個 FParamDelegateSignature 成員 spa

FParamDelegateSignature MyParameterDelegate;

這和以前同樣,建立一個委託實例做爲 GameMode 成員指針


而後建立一個 Actor 類,取名爲 ParamDelegateListener,code

在頭文件中添加如下聲明

UFUNCTION() void SetLightColor(FLinearColor LightColor); UPROPERTY() UPointLightComponent* PointLight;

ParamDelegateListener.cpp 

#include "Test.h" #include "UE4TestGameMode.h" #include "ParamDelegateListener.h"  
  
  
// Sets default values 
AParamDelegateListener::AParamDelegateListener() { // 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; PointLight = CreateDefaultSubobject<UPointLightComponent>("PointLight"); RootComponent = PointLight; } // Called when the game starts or when spawned 
void AParamDelegateListener::BeginPlay() { Super::BeginPlay(); UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld)); AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode); if (MyGameMode != nullptr) { // Binds a UObject-based member function delegate. UObject delegates keep a weak reference to your object. You can use ExecuteIfBound() to call them.(注意綁定的仍是 UFUNCTION) 
            MyGameMode->MyParameterDelegate.BindUObject(this, &AParamDelegateListener::SetLightColor); } } } // Called every frame 
void AParamDelegateListener::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); } // 1個參數 
void AParamDelegateListener::SetLightColor(FLinearColor LightColor) { PointLight->SetLightColor(LightColor); } 

回到 MyTriggerVollume.cpp,在 NotifyActorBeginOverlap 函數中添加如下代碼:orm

MyGameMode->MyParameterDelegate.ExecuteIfBound(FLinearColor(1, 0, 0, 1));    // 帶一個參數 

與以前不一樣的是,咱們須要多指定一個參數,參數類型和咱們以前的委託聲明一致。對象

 

 

顯然,MyTriggerVolume 壓根就無需知道 ParamDelegateListener 的存在,卻經過 GameMode 就能夠調用 ParamDelegateListener 的函數了,很大程度上下降了類間的耦合度。blog

 

解綁委託方式與以前相同,再也不贅述。it

4.經過委託綁定傳遞負載數據(Payload Data)

稍加修改,咱們就能夠在委託被調用時傳遞額外建立時的參數(additional creation-time parameter),即咱們在 MyTriggerVolume 中的調用方式不變,仍然是 ExecuteIfBound(FLinearColor(1, 0, 0, 1)),但能夠額外添加一些負載數據,在 ParamDelegateListener 中的 BindUObject 上添加。

 

首先修改 AParamDelegateListener::BeginPlay 中的 BindUObject,爲其添加一個 bool 負載數據

MyGameMode->MyParameterDelegate.BindUObject(this, &AParamDelegateListener::SetLightColor, false);

並修改 SetLightColor 的定義

UFUNCTION() void SetLightColor(FLinearColor LightColor, bool EnableLight);
// 2個參數 
void AParamDelegateListener::SetLightColor(FLinearColor LightColor, bool EnableLight) { PointLight->SetLightColor(LightColor); PointLight->SetVisibility(EnableLight); } 

注意:負載數據並不侷限於帶參數的委託,其餘的委託形式也能夠使用

 

 

5. 多播委託(Multicast Delegate)

以前說的委託,都是隻綁定了一個函數指針,而多播委託綁定的是一個函數指針集合,每一個函數指針都有對應的一個委託句柄,當廣播(Broadcast)委託的時候,他們將會被激活。

 

首先在 GameMode 中添加多播的委託聲明

須要明確聲明爲多播

DECLARE_MULTICAST_DELEGATE(FMulticastDelegateSignature)

接着在類中聲明一個 FMulticastDelegateSignature 成員

FMulticastDelegateSignature MyMulticastDelegate;

其次,建立一個新 Actor 類,命名爲 MulticastDelegateListener

 

在其頭文件中添加如下聲明:

FDelegateHandle MyDelegateHandle; UPROPERTY() UPointLightComponent* PointLight; UFUNCTION() void ToggleLight(); virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

大部分和以前的 Listener 類很類似,可是多一個 委託句柄實例,將用它來存儲委託實例的引用,咱們的添加(AddUObject)和移除(Remove)都須要它做爲參數

 

 源文件的代碼以下:

// Sets default values 
AMulticastDelegateListener::AMulticastDelegateListener() { // 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; PointLight = CreateDefaultSubobject<UPointLightComponent>("PointLight"); RootComponent = PointLight; } // Called when the game starts or when spawned 
void AMulticastDelegateListener::BeginPlay() { Super::BeginPlay(); UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld)); AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode); if (MyGameMode != nullptr) { // Adds a UObject-based member function delegate. UObject delegates keep a weak reference to your object. // 註冊一個對象方法 
            MyDelegateHandle = MyGameMode->MyMulticastDelegate.AddUObject(this, &AMulticastDelegateListener::ToggleLight); } } } // Called every frame 
void AMulticastDelegateListener::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); } void AMulticastDelegateListener::ToggleLight() { PointLight->ToggleVisibility(); } void AMulticastDelegateListener::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld)); AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode); if (MyGameMode != nullptr) { // Removes a function from this multi-cast delegate's invocation list (performance is O(N)). Note that the order of the delegates may not be preserved! 
            MyGameMode->MyMulticastDelegate.Remove(MyDelegateHandle); } } } 

MyTriggerVolume.cpp 的實現爲:

// Broadcasts this delegate to all bound objects, except to those that may have expired. 
MyGameMode->MyMulticastDelegate.Broadcast();

廣播函數很像咱們以前的 ExecuteIfBound函數,但有一點不一樣,它不須要檢查是否有函數綁定在委託上。

 

最後的效果是,若是咱們往場景中拖放了四五個MulticastDelegateListener,當咱們進入觸發區域,它們的燈會同時打開或關閉,由於每一個實例函數都被添加到委託集合當中;

若是拖放了四五個DelegateListener 到場景中,當咱們進入觸發區域,只有最後一個拖進場景的燈會亮,這是由於委託只綁定了最後一個實例函數。

相關文章
相關標籤/搜索