[UE4]事件處理(Handling Events)和委托(Delegate)代碼示例(一)


1. 通過重寫虛函數來處理事件

MyTriggerVolume.h

自定義一個Actor類,添加一個 Box 組件作為觸發區域,然后通過重寫虛函數——NotifyActorBeginOverlap, NotifyActorEndOverlap來響應事件
#pragma once  
  
#include "GameFramework/Actor.h"  
#include "MyTriggerVolume.generated.h"  
  
UCLASS()  
class TEST_API AMyTriggerVolume : public AActor  
{  
    GENERATED_BODY()  
      
public:   
    // Sets default values for this actor's properties  
    AMyTriggerVolume();  
  
    // Called when the game starts or when spawned  
    virtual void BeginPlay() override;  
      
    // Called every frame  
    virtual void Tick( float DeltaSeconds ) override;  
  
    UPROPERTY()  
    UBoxComponent* TriggerZone;  
      
    UFUNCTION()  
    virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;  
    UFUNCTION()  
    virtual void NotifyActorEndOverlap(AActor* OtherActor) override;  
};  

MyTriggerVolume.cpp

#include "Test.h"  
#include "UE4TestGameMode.h"  
#include "MyTriggerVolume.h"  
  
  
// Sets default values  
AMyTriggerVolume::AMyTriggerVolume()  
{  
    // 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;  
    TriggerZone = CreateDefaultSubobject<UBoxComponent>("TriggerZone");  
    TriggerZone->SetBoxExtent(FVector(200, 200, 100));// 設置觸發區域的范圍  
}  
  
// Called when the game starts or when spawned  
void AMyTriggerVolume::BeginPlay()  
{  
    Super::BeginPlay();  
      
}  
  
// Called every frame  
void AMyTriggerVolume::Tick( float DeltaTime )  
{  
    Super::Tick( DeltaTime );  
  
}  
  
// 重寫虛函數來響應事件  
void AMyTriggerVolume::NotifyActorBeginOverlap(AActor* OtherActor)  
{  
    GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, FString::Printf(TEXT("%s entered me"), *(OtherActor->GetName())));// 注意FString::Format需要解引用  
}  
// 重寫虛函數來響應事件  
void AMyTriggerVolume::NotifyActorEndOverlap(AActor* OtherActor)  
{  
    GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, FString::Printf(TEXT("%s left me"), *(OtherActor->GetName())));  
}  

2. 綁定在 UFUNCTION 函數上的委托(不帶參數)

委托的好處在於,我們不用知道當前指派的函數的細節就可以調用它,它是一種安全版本的函數指針。

 

以下代碼將展示如何關聯 UFUNCTION 到一個委托上,即委托執行時,UFUNCTION 將被調用。
(效果為 當玩家進入觸發區域,點光源亮)

 

首先在 UE4TestGameMode.h 中添加一個委托聲明(在 UCLASS 之前),如下:

DECLARE_DELEGATE(FStandardDelegateSignature)  

然后,為 UE4TestGameMode 類添加一個新成員

FStandardDelegateSignature MyStandardDelegate;  

接着,我們新建一個 Actor 類——DelegateListener,主要實現具體方法,以及負責委托的綁定和解綁 

DelegateListener.h

UCLASS()  
class TEST_API ADelegateListener : public AActor  
{  
    GENERATED_BODY()  
      
public:   
    // Sets default values for this actor's properties  
    ADelegateListener();  
  
    // Called when the game starts or when spawned  
    virtual void BeginPlay() override;  
      
    // Called every frame  
    virtual void Tick( float DeltaSeconds ) override;  
      
    UFUNCTION()  
    void EnableLight();  
  
    UFUNCTION()  
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;  
  
    UPROPERTY()  
    UPointLightComponent* PointLight;  
      
};  

DelegateListener.cpp

#include "Test.h"  
#include "UE4TestGameMode.h" // 注意 include 的位置  
#include "DelegateListener.h"  
  
  
// Sets default values  
ADelegateListener::ADelegateListener()  
{  
    // 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;  
      
    PointLight->SetVisibility(false);  
}  
  
// Called when the game starts or when spawned  
void ADelegateListener::BeginPlay()  
{  
    Super::BeginPlay();  
    UWorld* TheWorld = GetWorld();  
    if (TheWorld != nullptr)  
    {  
        AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld));  
        AUE4TestGameMode * MyGameMode = Cast<AUE4TestkGameMode>(GameMode);  
        if (MyGameMode != nullptr)  
        {  
            // ❤ 綁定一個基於 UObject 的成員函數的委托。UObject 委托保留了一個弱引用在你的對象上,可以通過.ExecuteIfBound() 來調用委托的函數  
            MyGameMode->MyStandardDelegate.BindUObject(this, &ADelegateListener::EnableLight);// 其實就是將 EnableLight 函數綁定在了委托上。  
                 }  
    }  
  
}  
  
// Called every frame  
void ADelegateListener::Tick( float DeltaTime )  
{  
    Super::Tick( DeltaTime );  
  
}  
  
void ADelegateListener::EnableLight()  
{  
    PointLight->SetVisibility(true);  
}  
  
void ADelegateListener::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)  
        {  
            // 解綁委托  
            MyGameMode->MyStandardDelegate.Unbind();  
        }  
    }  
}  

值得注意的是,如果我們綁定的是普通的C++函數,那么就應該將 BindUObject 改為 BindRaw,如果是靜態方法,那就改為 BindStatic。

 

最后,回到我們之前的 MyTriggerVolume.cpp, 利用 GameMode(我們之前聲明委托和定義委托成員的地方) 執行委托,

在 NotifyActorBeginOverlap 方法中添加以下代碼:

UWorld* TheWorld = GetWorld();  
if (TheWorld != nullptr)  
{  
    AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld));  
    AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode);  
    // ❤ 執行委托的函數  
    MyGameMode->MyStandardDelegate.ExecuteIfBound();  
}  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM