3. 创建带参数的委托

我们可以通过修改委托的签名来使其接受参数

比如我们需要接受一个参数的话,可以在 GameMode 中这样声明:

DECLARE_DELEGATE_OneParam(FParamDelegateSignature, FLinearColor)  

注意:这个宏与之前稍有不同,后缀多出了一个 _OneParam ,而且我们还需要指定接受参数的类型——本例为 FLinearColor

接着再添加一个 FParamDelegateSignature 成员

FParamDelegateSignature MyParameterDelegate;     

这和之前一样,创建一个委托实例作为 GameMode 成员

然后创建一个 Actor 类,取名为 ParamDelegateListener,

在头文件中添加以下声明

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 函数中添加以下代码:

MyGameMode->MyParameterDelegate.ExecuteIfBound(FLinearColor(, , , ));    // 带一个参数  

与之前不同的是,我们需要多指定一个参数,参数类型和我们之前的委托声明一致。

显然,MyTriggerVolume 压根就无需知道 ParamDelegateListener 的存在,却通过 GameMode 就可以调用 ParamDelegateListener 的函数了,很大程度上降低了类间的耦合度。

解绑委托方式与之前相同,不再赘述。

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 到场景中,当我们进入触发区域,只有最后一个拖进场景的灯会亮,这是因为委托只绑定了最后一个实例函数。

[UE4]事件处理(Handling Events)和委托(Delegate)代码示例(二)【C++】的更多相关文章

  1. [UE4]事件处理(Handling Events)和委托(Delegate)代码示例(一)

    1. 通过重写虚函数来处理事件 MyTriggerVolume.h 自定义一个Actor类,添加一个 Box 组件作为触发区域,然后通过重写虚函数——NotifyActorBeginOverlap, ...

  2. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  3. 关于C# 委托(delegate)与事件(event)的用法及事例

    C#中的委托和事件对于新手可能会有一点难理解,所以先从一个小例子入手,以便能更好的理解其如何使用.有一个学生每天定闹钟在早上6点起床,所以当每天早上6点的时候,闹钟就会响起来,从而学生才会按时起床. ...

  4. C# 委托Delegate(一) 基础介绍&用法

    本文是根据书本&网络 前人总结的. 1. 前言 定义&介绍: 委托Delegate是一个类,定义了方法的类型, 使得可以将方法当做另一个方法的参数来进行传递,这种将方法动态地赋给参数的 ...

  5. C#基础知识六之委托(delegate、Action、Func、predicate)

    1. 什么是委托 官方解释 委托是定义方法签名的类型,当实例化委托时,您可以将其实例化与任何具有兼容签名的方法想关联,可以通过委托实例调用方法. 个人理解 委托通俗一点说就是把一件事情交给别人来帮助完 ...

  6. 为什么不能把委托(delegate)放在一个接口(interface)当中?

    stackoverflow上有人问,为什么不能把委托放在一个接口当中? 投票最多的第一个答案第一句话说,“A Delegate is just another type, so you don't g ...

  7. C# 代理/委托 Delegate

    本文转载自努力,努力,努力 1. 委托的定义:委托是函数的封装,它代表一"类"函数.他们都符合一定的签名:拥有相同的参数列表,返回值类型.同时,委托也可以看成是对函数的抽象,是函数 ...

  8. 深入理解委托(Delegate)

    前言 委托其实一直以来都感觉自己应该挺熟悉的,直到最近又去翻了翻 CLR via C#,感觉我之前的理解可能还有失偏颇.在这记录一下. 之前文章的链接: 接口和委托的泛型可变性 C#高级编程笔记 De ...

  9. C# -- 使用委托 delegate 执行异步操作

    C# -- 使用委托 delegate 执行异步操作 委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似. 与 C 中的函数指针不同,委托是面向对象的.类型安全的和保险的. 委托的 ...

随机推荐

  1. 2014.04.14 Lastpass活动,2年高级版

    点击进入活动地址. 我的邀请地址,^_^

  2. STL标准库-Tuple

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 在前面我介绍过一次tuple,今天在书上也看到了tuple,那就在写一次吧. tuple(元组),他的内部可以放任意类型的变量( ...

  3. eclipse集成svn后总是弹出 Password Required问题解决方法

    最近在集成svn后,在打开eclipse后总是一遍遍的弹出 Password Required,即使输入正确的用户名以及密码也会弹出,最后发现是eclipse的Network  Connections ...

  4. 移动前端开发之viewport的深入理解 --- 待续

    在移动设备上进行网页的重构或开发, 只有明白了viewport的概念 才能 响应 各种  不同分辨率 的移动设备 一.viewport的概念 通俗的讲,移动设备上的viewport就是设备的屏幕上能用 ...

  5. IOS延时加载网络图片

        重网上下载图片是很慢的,为了不影响体验,选择延时加载图片是很好的办法. 一个tableView 列表,左边暂时没有图 - (UITableViewCell *)tableView:(UITab ...

  6. 【Genymotion】add a new virtual device 失败

    Genymotion 新增虚拟设备(模拟器)时,由于网络原因,总是下载失败,如图: 下载失败提示“Unable to create virtual device: Connection timeout ...

  7. linux下源码安装jdk1.8和tomcat8.5

    Java是目前可移植性较高的语言,相当火热,tomcat运行就需要Java语言环境 0.java简介 1)tomcat运行需要对应的Java环境,Java环境通过安装jdk来获得2)为了防止兼容性问题 ...

  8. 转:Linux实时将所有输出重定向到文件

    转自: Linux的重定向机制十分好用,我们经常需要在服务器上挂起一个服务程序,然后将该程序的所有输出重定向到某个文件,这样即使我们注销了用户,程序依然在linux服务器上运行着. 但是重定向的输出经 ...

  9. CF1142E/1143B Lynyrd Skynyrd

    CF1142E/1143B Lynyrd Skynyrd 开始读错题了,以为是连续的一段,敲完后才发现是 \(subsequence\) ... 考虑对于 \(a\) 中的每个 \(a_i\) 找到它 ...

  10. C# Dictionary源码剖析

    参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/wangjun1234/p/3719 ...