事件处理(Handling Events)和委托(Delegate)代码示例(一)【UE4】【C++】
发布日期:2021-07-01 05:53:52 浏览次数:2 分类:技术文章

本文共 4708 字,大约阅读时间需要 15 分钟。

 

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 valuesAMyTriggerVolume::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
("TriggerZone"); TriggerZone->SetBoxExtent(FVector(200, 200, 100));// 设置触发区域的范围}// Called when the game starts or when spawnedvoid AMyTriggerVolume::BeginPlay(){ Super::BeginPlay(); }// Called every framevoid 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 valuesADelegateListener::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
("PointLight"); RootComponent = PointLight; PointLight->SetVisibility(false);}// Called when the game starts or when spawnedvoid ADelegateListener::BeginPlay(){ Super::BeginPlay(); UWorld* TheWorld = GetWorld(); if (TheWorld != nullptr) { AGameMode* GameMode = Cast
(UGameplayStatics::GetGameMode(TheWorld)); AUE4TestGameMode * MyGameMode = Cast
(GameMode); if (MyGameMode != nullptr) { // ❤ 绑定一个基于 UObject 的成员函数的委托。UObject 委托保留了一个弱引用在你的对象上,可以通过.ExecuteIfBound() 来调用委托的函数 MyGameMode->MyStandardDelegate.BindUObject(this, &ADelegateListener::EnableLight);// 其实就是将 EnableLight 函数绑定在了委托上。 } }}// Called every framevoid 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
(UGameplayStatics::GetGameMode(TheWorld)); AUE4TestGameMode * MyGameMode = Cast
(GameMode); if (MyGameMode != nullptr) { // 解绑委托 MyGameMode->MyStandardDelegate.Unbind(); } }}

 

 

值得注意的是,如果我们绑定的是普通的C++函数,那么就应该将 BindUObject 改为 BindRaw,如果是静态方法,那就改为 BindStatic。

 

最后,回到我们之前的 MyTriggerVolume.cpp, 利用 GameMode(我们之前声明委托和定义委托成员的地方) 执行委托,

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

 

 

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

 

 

(未完待续)

 

转载地址:https://panda1234lee.blog.csdn.net/article/details/63834770 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:事件处理(Handling Events)和委托(Delegate)代码示例(二)【UE4】【C++】
下一篇:后期材质(PostProcess Material)+ Custom Node 实现"描边"和"马赛克"效果【UE4】

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月22日 09时20分48秒