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 到場景中,當咱們進入觸發區域,只有最後一個拖進場景的燈會亮,這是由於委託只綁定了最後一個實例函數。