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(); }