C++中自定义事件与委托

自定义事件,和委托其实是一类操作。
在蓝图中都表现为红色方块。
自定义事件通过DECLARE_EVENT(ClassName, EventName)来创建一个属于ClassName的EventName事件。可以看出一般是没有参数的,如果蓝图中或者C++代码中自带的BeginPlay.
自定义事件
而委托则是通过DECLARE_DYNAMIC_MULTICAST_DELEGATE_'FourParams'来创建的需要根据参数个数更改FourParams。类似蓝图或者C++代码中自带的OnComponentBeginOverlap,OnComponentHit等等
委托
参考
委托和事件都相当于一个传输消息(触发点),一个接受消息(执行点)
绑定操作
这一步相当于蓝图中那些事件发生后要进行的操作,比如OnComponentHit后为了销毁粒子,那么就需要在蓝图中设置方块,连线。而在C++代码中,则需要对于有这个委托或者事件的Actor进行调用,添加设置的函数。
//对于自定义事件
Actor->EventName.AddUobject(this,&Class::Func);
//对于委托
Actor->EventName.AddDynamic(this,&Class::Func);
具体步骤
对于触发点
编写红色方块
- 声明委托或者事件(委托需要定义一个参数列表)
- 声明一个委托或者事件对象(相当于实例化一个类)--类似USphereComponent* SphereComp;
- 在需要的位置触发事件或者委托(执行或者广播),委托需要传入参数
对于执行点
一般在其他写的类中,即蓝图中红色方块之后的操作
- 利用上文绑定一些这些委托需要做的函数
- 编写函数原型
稍微综合一点就是,在一个类中实现委托或者事件的声明和调用(广播),在另一个需要操作的类中实现函数并绑定到委托或者事件中。
我们在一个ActorComponent类中声明了一个委托,并在其对应的.cpp文件中进行了广播,这个委托主要处理当生命值发生变化时的一些操作。


然后我们在Actor中绑定组件,这样在蓝图中就会显示出这个委托

接着我们在C++代码中定义了一个函数来进行角色死亡之后的操作

注意:要绑定到委托的函数的形参个数必须和委托的形参数量一致
然后利用AddDynamic绑定

重新编译后回到蓝图,就可以发现这个委托拥有了函数IsDied

而如果不适用绑定,那么就可以在蓝图中从这个委托事件连线,实现c++代码的模块连接就可以了,有点类似于将蓝图模块写好然后利用Collapse to Function使得功能变为一个Function,只不过我们直接在C++中操作了。
那么这样看来委托其实就是函数,但他相对于函数的优点就在于当发生这个事件时,会对Actor产生影响,而我们使用代理相当于时直接调用,不用传入自身self的引用。而我们使用函数,就需要确定这个函数对谁进行了操作。相当于一种解耦。
将一个普适性的东西使用委托,有利于解耦。
分类
委托分为单播,多播,动态,动态多播,事件(可以看到事件其实就是一种委托)
- 单播
在执行点绑定函数时只能绑定一个函数,比如上方示例如果绑定了IsDied就不可以绑定其他函数了,而如果绑定了多个就选择最后一个。
其一般的绑定方式为Bind*
可以拥有返回值。
在参考中有这样一个例子
DECLARE_DELEGATE_OneParam(FTestDelegate, int);
static void StaticDelegateProc(int nCode)
{
UE_LOG(LogTemp, Log, TEXT("StaticDelegateProc : %d"), nCode);
}
FTestDelegate DelegateObj1;
//绑定函数
DelegateObj1.BindStatic(StaticDelegateProc);
//通过ExcuteIfBound方法执行
DelegateObj1.ExecuteIfBound(1);
- 多播
DECLARE_MULTICAST_DELEGATE_XXXPARAMS
一般通过Add*来绑定函数,而其不会有返回值,只能通过广播来调用。
广播Broadcast()其实就是执行函数,这个委托通过Add绑定的所用函数都会被执行,我们再来看之前那个例子(虽然不是)
bool USAttributeComponent::ApplyHealthChange(float Delta)
{
if (Health <= 100.0f && Delta < 0.0f) {
Health += Delta;
OnHealthChanged.Broadcast(nullptr, this, Health, Delta);
}
if (Health < 100.0f && Delta > 0.0f) {
Health += Delta;
OnHealthChanged.Broadcast(nullptr, this, Health, Delta);
}
return true;
}
先对生命进行扣血或者加血,然后调用委托,而现在只绑定了一个函数就是IsDied,相当于就是
if (Health <= 100.0f && Delta < 0.0f) {
Health += Delta;
IsDied();
}
如果绑定了多个函数,需要注意执行顺序可能与函数的添加顺序不相同。
多播
事件
事件就是一个多播委托。

需要注意的是事件的Broadcast()只对事件所在的类有效,所以为了在想要触发事件的位置调用事件需要新建一个接口将Broadcast()放入其中。
事件动态委托和动态多播委托
主要区别就是动态委托可以在蓝图中调用,就是我们的例子,注意动态多播委托只能作为变量给蓝图调用,不能作为函数参数,而动态委托可以作为函数参数
动态单播:DECLARE_DYNAMIC_DELEGATE_XXXPARAMS
动态多播:DECLARE_DYNAMIC_MULTICAST_DELEGATE_XXXPARAM
动态委托
小结
我们使用了动态多播委托,在C++中绑定了函数给委托,并且在ApplyHealthChange函数执行时,广播了这个委托(执行函数),判断当前角色血量这个操作。
那么在蓝图中如何绑定一个函数(事件)给这个动态多播委托呢?
参考

可以看到OnMyDelegate2为我们的动态多播委托,而charDelegate为我们要绑定的事件,类似我们写的IsDied函数。
之后继续在委托编写的类中定义了一个触发委托广播的函数TestBpDelegate,在蓝图中使用按键来执行。

C++中自定义事件与委托的更多相关文章
- 1 .net中自定义事件的步骤
1 申明一个自定义的类并且继承事件的基类 public class ClientSocketModelConnectedEvent:EventArgs { private string param; ...
- 《C#高级编程》学习笔记------C#中的事件和委托
本文转载自张子阳 目录 委托的作用 将方法绑定到委托 事件的来由 Observer设计模式 .Net Framework中的委托与事件 引言 委托 和 事件在 .Net Framework中的应用 ...
- Extjs中自定义事件
//Ext中所谓的响应事件,响应的主要是组件中已经定义的事件(通过看api各组件的events可以找到) //主要作用就是利用on调用各组件的事件处理函数,然后在函数中作用户想要的操作 ...
- javascript中自定义事件
自定义事件:用户可以指定事件类型,这个类型实际上就是一个字符串,然后为这个类型的事件指定事件处理函数,可以注册多个事件处理函数(用数组管理),调用时,从多个事件处理函数中找到再调用. function ...
- 使用jQuery在javascript中自定义事件
js中的自定义事件有attachEvent,addEventListener等等好多种,往往受困于浏览器兼容,而且代码写起来也相当麻烦.jQuery为我们解决了这个问题,几行代码就可以很好的实现事件的 ...
- php中自定义事件---事件驱动
PHP中自定义事件驱动,处理机制. 原文:https://www.cnblogs.com/mafeifan/p/4322271.html ------------------------------- ...
- Vue中调用另一个组件中自定义事件
之前在一个场景中,遇到组件需要调用父组件中的方法tableInit(),字组件调用父组件常用的有三种方法,具体参考:https://www.cnblogs.com/jin-zhe/p/9523782. ...
- js中自定义事件,使用了jQuery
$(function(){ $('#btn').bind("myClick", function(){ //自定义myClick事件 $('#test').append(" ...
- JS中自定义事件的使用与触发
1. 事件的创建 JS中,最简单的创建事件方法,是使用Event构造器: var myEvent = new Event('event_name'); 但是为了能够传递数据,就需要使用 CustomE ...
- JavaScript中的事件代理/委托
事件委托在JS高级程序设计中的定义为"利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件" 如何理解上面的这句话呢,在网上,大牛们一般都使用收快递这个例子来解释的, ...
随机推荐
- MVVM模式的理解
MVVM模式的理解 MVVM全称Model-View-ViewModel是基于MVC和MVP体系结构模式的改进,MVVM就是MVC模式中的View的状态和行为抽象化,将视图UI和业务逻辑分开,更清楚地 ...
- MySQL数据库备份与恢复方法
MySQL数据库备份与恢复方法 mysql -uroot -p show databases; 1.导出数据库 1).MySQL命令行导出整个数据库(包含数据) 导出文件默认是存在mysql\bin目 ...
- java zTree异步加载实战
zTree简介 zTree 是一个依靠 jQuery 实现的多功能 "树插件".优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. zTree 是开源免费的软件(MI ...
- Java I/O 教程(十) ObjectOutputStream和ObjectInputStream
ObjectOutputStream ObjectOutputStream用于往输出流中写入原始类型和Java对象. 类定义 public class ObjectOutputStream exten ...
- python文件加锁模块之fcntl
# 示例 import fcntl with open('./test.txt', 'w') as f: fcntl.flock(f, fcntl.LOCK_EX) # 对文件加锁,除加锁进程外其它进 ...
- 【Azure Data Lake Storage】如何才能保留Blob中的文件目录结构(即使文件夹中文件数量为0的情况下)?
问题描述 在使用Azure Storage Account Blob时候,发现当文件夹中的Blob(文件)被全部输出后,文件夹也会消失? 为什么它不能像Windows系统中的文件夹一样,即使是一个空文 ...
- 【Azure 环境】中国区Azure B2C 是否支持手机验证码登录呢?
问题描述 中国区Azure B2C 是否支持手机验证码登录呢? 问题回答 在没有原生 Phone sign-up and sign-in for user flows (中国区不支持,Global A ...
- C#多线程(7):手动线程通知
目录 区别与示例 ManualResetEvent 类 ManualResetEventSlim 区别与示例 AutoResetEvent 和 ManualResetEvent 十分相似.两者之间的区 ...
- C++异常的基本概念与用法
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try{}内写可能会抛出异常的代码.catch(类型){处理} 写异常类型和异常处理 抛出 ...
- Java 泛型举例
1 package com.bytezero.genericity; 2 3 import org.junit.Test; 4 5 import java.util.*; 6 7 /** 8 * @a ...