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. struts2.properties

    #action后缀struts.action.extension=action#上传文件的工作目录与文件的最大尺寸struts.multipart.saveDir=struts.multipart.m ...

  2. ZooKeeper 之 zkCli.sh客户端的命令使用

    zkCli.sh的使用 ZooKeeper服务器简历客户端 ./zkCli.sh -timeout 0 -r -server ip:port ./zkCli.sh -timeout 5000 -ser ...

  3. block ,GCD(转)

    原文:http://blog.sina.com.cn/s/blog_45e2b66c01010dhd.html 1.GCD之dispatch queue http://www.cnblogs.com/ ...

  4. 图解SQL的inner join、left join、right join、full outer join、union、union all的区别【转载】

    对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Codin ...

  5. C++ 内存拷贝函数 memcpy

    在C/C++中经常会遇到对一段固定的连续内存进行拷贝操作,   这时候我们就需要用到   <cstring>  头文件  中的  memcpy  函数. 具体使用如下: 其中   ,   ...

  6. Unity 3D开发-C#脚本语言的一些基础用法

    Unity 中C#语言的一些基础用法 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Lerp -- 线 ...

  7. HDU 1084:What Is Your Grade?

    Problem Description "Point, point, life of student!" This is a ballad(歌谣)well known in col ...

  8. ElasticSearch(八):springboot集成ElasticSearch集群并使用

    1. 集群的搭建 见:ElasticSearch(七) 2. springboot配置集群 2.1 创建springboot项目,使用idea创建,不过多介绍(创建项目时候建议不要勾选elastics ...

  9. CTF之常见的两种关于word的信息隐藏技术

    一.利用word本身自带的文字隐藏功能 1.在word中输入文字 2.选中文字,单击右键,选择字体选项 3.单击字体选项后,单击隐藏,确定 查找隐藏信息 1.单击左上角WPS文字后,选择选项按钮单击 ...

  10. TensorFlow笔记-01-开篇概述

    人工智能实践:TensorFlow笔记-01-开篇概述 从今天开始,从零开始学习TensorFlow,有相同兴趣的同志,可以互相学习笔记,本篇是开篇介绍 Tensorflow,已经人工智能领域的一些名 ...