自定义事件,和委托其实是一类操作。

在蓝图中都表现为红色方块。

自定义事件通过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);

具体步骤

对于触发点

编写红色方块

  1. 声明委托或者事件(委托需要定义一个参数列表)
  2. 声明一个委托或者事件对象(相当于实例化一个类)--类似USphereComponent* SphereComp;
  3. 在需要的位置触发事件或者委托(执行或者广播),委托需要传入参数

对于执行点

一般在其他写的类中,即蓝图中红色方块之后的操作

  1. 利用上文绑定一些这些委托需要做的函数
  2. 编写函数原型

稍微综合一点就是,在一个类中实现委托或者事件的声明和调用(广播),在另一个需要操作的类中实现函数并绑定到委托或者事件中。

我们在一个ActorComponent类中声明了一个委托,并在其对应的.cpp文件中进行了广播,这个委托主要处理当生命值发生变化时的一些操作。





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



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



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

然后利用AddDynamic绑定



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



而如果不适用绑定,那么就可以在蓝图中从这个委托事件连线,实现c++代码的模块连接就可以了,有点类似于将蓝图模块写好然后利用Collapse to Function使得功能变为一个Function,只不过我们直接在C++中操作了。

那么这样看来委托其实就是函数,但他相对于函数的优点就在于当发生这个事件时,会对Actor产生影响,而我们使用代理相当于时直接调用,不用传入自身self的引用。而我们使用函数,就需要确定这个函数对谁进行了操作。相当于一种解耦。

将一个普适性的东西使用委托,有利于解耦。

分类

委托分为单播,多播,动态,动态多播,事件(可以看到事件其实就是一种委托)

  1. 单播

    在执行点绑定函数时只能绑定一个函数,比如上方示例如果绑定了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);
  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();
}

如果绑定了多个函数,需要注意执行顺序可能与函数的添加顺序不相同。

多播

  1. 事件

    事件就是一个多播委托。



    需要注意的是事件的Broadcast()只对事件所在的类有效,所以为了在想要触发事件的位置调用事件需要新建一个接口将Broadcast()放入其中。

    事件

  2. 动态委托和动态多播委托

    主要区别就是动态委托可以在蓝图中调用,就是我们的例子,注意动态多播委托只能作为变量给蓝图调用,不能作为函数参数,而动态委托可以作为函数参数

    动态单播:DECLARE_DYNAMIC_DELEGATE_XXXPARAMS

    动态多播:DECLARE_DYNAMIC_MULTICAST_DELEGATE_XXXPARAM

    动态委托

小结

我们使用了动态多播委托,在C++中绑定了函数给委托,并且在ApplyHealthChange函数执行时,广播了这个委托(执行函数),判断当前角色血量这个操作。

那么在蓝图中如何绑定一个函数(事件)给这个动态多播委托呢?

参考



可以看到OnMyDelegate2为我们的动态多播委托,而charDelegate为我们要绑定的事件,类似我们写的IsDied函数。

之后继续在委托编写的类中定义了一个触发委托广播的函数TestBpDelegate,在蓝图中使用按键来执行。

C++中自定义事件与委托的更多相关文章

  1. 1 .net中自定义事件的步骤

    1 申明一个自定义的类并且继承事件的基类 public class ClientSocketModelConnectedEvent:EventArgs { private string param; ...

  2. 《C#高级编程》学习笔记------C#中的事件和委托

    本文转载自张子阳 目录 委托的作用 将方法绑定到委托 事件的来由 Observer设计模式 .Net Framework中的委托与事件   引言 委托 和 事件在 .Net Framework中的应用 ...

  3. Extjs中自定义事件

    //Ext中所谓的响应事件,响应的主要是组件中已经定义的事件(通过看api各组件的events可以找到)         //主要作用就是利用on调用各组件的事件处理函数,然后在函数中作用户想要的操作 ...

  4. javascript中自定义事件

    自定义事件:用户可以指定事件类型,这个类型实际上就是一个字符串,然后为这个类型的事件指定事件处理函数,可以注册多个事件处理函数(用数组管理),调用时,从多个事件处理函数中找到再调用. function ...

  5. 使用jQuery在javascript中自定义事件

    js中的自定义事件有attachEvent,addEventListener等等好多种,往往受困于浏览器兼容,而且代码写起来也相当麻烦.jQuery为我们解决了这个问题,几行代码就可以很好的实现事件的 ...

  6. php中自定义事件---事件驱动

    PHP中自定义事件驱动,处理机制. 原文:https://www.cnblogs.com/mafeifan/p/4322271.html ------------------------------- ...

  7. Vue中调用另一个组件中自定义事件

    之前在一个场景中,遇到组件需要调用父组件中的方法tableInit(),字组件调用父组件常用的有三种方法,具体参考:https://www.cnblogs.com/jin-zhe/p/9523782. ...

  8. js中自定义事件,使用了jQuery

    $(function(){ $('#btn').bind("myClick", function(){ //自定义myClick事件 $('#test').append(" ...

  9. JS中自定义事件的使用与触发

    1. 事件的创建 JS中,最简单的创建事件方法,是使用Event构造器: var myEvent = new Event('event_name'); 但是为了能够传递数据,就需要使用 CustomE ...

  10. JavaScript中的事件代理/委托

    事件委托在JS高级程序设计中的定义为"利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件" 如何理解上面的这句话呢,在网上,大牛们一般都使用收快递这个例子来解释的, ...

随机推荐

  1. Springboot+Freemarker+Boostrap实现用户增删改查实战

    说明 做java web用的2大模板语言分别是:thymeleaf和freemarker,thymeleaf前面已经用了很多了,所以今天用一下这个freemarker. 技术栈 springboot ...

  2. ORA-12514问题解决

    版本:11.2.0.1.0 - 64bit 本机安装Oracle后链接测试发现以下情况: sqlplus scott/tiger 正常登陆 sqlplus scott/tiger@orcl  登陆失败 ...

  3. std::async 与 std::thread 在什么时候使用比较合适

    前提: C++ 11 中提供了多线程的标准库,提供了管理线程.保护共享数据.线程间同步操作.原子操作等类.多线程库对应的头文件是 #include <thread>,类名为 std::th ...

  4. Miniconda安装和使用

    Miniconda概述 Miniconda是什么? 要解释Miniconda是什么,先要弄清楚什么是Anaconda,它们之间的关系是什么? 而要知道Anaconda是什么,最先要明白的是搞清楚什么是 ...

  5. 【小记事】如何设置vscode代码格式化时不要自动换行

    最近一格式化就给我分好多行,好气哦(`ヘ´)=3 在setting.json中添加如下代码: "vetur.format.defaultFormatter.html": " ...

  6. 【系统设计】集团内部HR系统完结,项目从0到1总结

    最近一年学习了PMP,结合下PMP的知识,分享一下最近HR项目的全生命周期流程管理(需求分析.产品设计.系统开发.测试.上线.运营). 先一句话概括:战略分析-收集需求-流程梳理-关键需求-IT规划- ...

  7. iOS日志操作与开发,你真的会重视吗

    iOS中常用日志和上报系统浅析 类CocoaLumberjack日志框架架构浅析 Crash的类型介绍和常用收集方案 常用上报技术方案对比和分析

  8. STL-unordered_map,unordered_set模拟实现

    unordered_set #pragma once #include"28hashtable_container.h" namespace test { //template & ...

  9. Rust 登上了开源头条「GitHub 热点速览」

    抱歉!上周因为出月刊工作量比较大,所以「GitHub 热点速递」暂停了一期,必须要给守着更新的读者道个歉,以后每周二的「热点速递」会按时更新,下不为例. 说回本周的热门开源项目,Rust 语言可谓是出 ...

  10. 借助 Terraform 功能协调部署 CI/CD 流水线-Part 2

    在第一部分的文章中,我们介绍了3个步骤,完成了教程的基础配置: 使用 Terraform 创建 AWS EKS Infra 在 EKS 集群上部署 ArgoCD 及其依赖项 设置 Bitbucket ...