什么是委托?
我们先来看看官方的解释:
委托 是一种泛型但类型安全的方式,可在C++对象上调用成员函数。可使用委托动态绑定到任意对象的成员函数,之后在该对象上调用函数,即使调用程序不知对象类型也可进行操作。复制委托对象很安全。你也可以利用值传递委托,但这样操作需要在堆上分配内存,因此通常并不推荐。请尽量通过引用传递委托。虚幻引擎共支持三种类型的委托:单播委托,多播委托,和动态委托。
光是看定义可能不是很好理解,我们知道在计网中,单播和多播的意思是主机之间的一对一或者多对多通讯,在UE4中我们没有主机,所以并不是计网中的意思
单播委托的意思就是可以使用一个Actor事件绑定到另外一个Actor某个函数,即可以调用不知道该对象类型的函数。
(图取自B站up唯乐来了)
对于实现一个开关门/灯的过程来说,就是我们可以设置一个Trigger,通过绑定Trigger与门,来实现当碰撞触发或者重叠触发等事件只要触发Trigger以后就可以调用到门的函数,从而来实现开关门。
就这这个例子,我们来看看委托是如何实现的:
加入当一个委托被建立完毕之后,它不会通过Trigger直接把委托信息传送给门,而是先会把委托信息传递给一个管理委托系统,通过管理委托系统再将信息传递给绑定委托的物体。这里使用管理委托的原因很简单,当一个游戏中所需要委托太多,如果不使用一个系统对其进行管理,那将会变得非常的混乱。
首先我们要知道管理委托的系统在UE4中叫做声明委托
为了声明委托,我们要设置一个默认的GameMode,将声明委托放在里面。

我们要做的是,新建一个GameMode(一般新建项目都会有,直接用),然后记得,打开你的地图,WorldSettting里面把GameMode改成自己的GameMode(默认是无)这里非常重要!
然后如黄色框所示,我们需要声明一个委托,第一个参数是委托名,委托名是自己可定义的,至于如果你所需要声明的委托需要传参数,就在后面添加_XXXParam(XXX指需要传参数的个数),如果要声明多播就在中间加上_MULTICAST。
这样我们就知道,我们黄色部分声明的是一个 多播的,有一个bool参数的,委托名为FMyTrigger(为了符合UE中命名规则,前面加上F)的委托。
声明完之后,我们在红色部分对于进行实例化(使用Public关键字,因为我们希望其他类对他进行调用)
声明完委托以后,我们就要对委托进行绑定了。
我们首先新建一个名为MyDoor的Actor,然后在其中加入StaticMeshComponent,然后我们定义一个DoorState函数,当Trigger事件触发之后,我们调用DoorState函数,用来对门进行开关。

MyDoor.Cpp实现:

这里重点讲解下红色框部分,
我们要绑定某个函数首先就要先找到我们的委托名,我们的委托名定义在自定义的GameMode里面
所以我们使用GetWorld()再使用GetGamoMode得到GameMode的父类AGameModeBase,再通过Cast<>操作得到继承自AGameModeBase的我们的子类AUE_ProjectGameModeBase.
要实现绑定,我们只需要再MyTrigger执行特定的方法:这里是多播绑定,所以使用的是AddUObject(,)后面的参数是传递函数的引用
当然,对于单播委托,还有更多的绑定方法:

这里的OpenDoor和CloseDoor函数,我们想通过蓝图实现从而达到渐渐开门的效果,蓝图实现如下:

至此,我们的委托绑定就已经完成了。
我们再来看看如何执行委托

在上面一个蓝色框,我们定义了一个BoxComponent用来得到碰撞事件,从而触发委托,在红色框是我们的执行委托函数,这里我们要传递一个参数value(这也是为什么我们开始声明时需要声明一个参数的原因)

执行委托部分,我们也要调用自己的委托关键字,所以前面与绑定委托一致,就不再赘述,唯一不同的地方就是红色框,这里我们时多播,所以执行的时Broadcast,这会把信息广播给所有已经绑定的对象,如果是单播时有如下:

当然,我们最后仅仅只是把执行广播写在了碰撞事件里面,我们要完成执行还需要重写碰撞事件(上上图蓝色框):

这里我们将BeginOverlap和EndOverlap分别绑定到我们写的函数上。
你会发现在我这里会有很多的参数,虽然都用不到。但是这里的参数的必须的(还没搞清楚为什么)
要怎么得到这个参数呢?我们已BeginOverlap为例,我们使用IDE自带的查看详细代码的功能(ctrl+ 鼠标左键),
我们打开OnComponentBeginOverlap(如下图红色框所示)

打开之后我们发现它其实也是一个东西的实例,我们再对这个进行打开

得到这个后缀为SixParams的东西的声明,我们取它的后12位参数(参数的名字与类型是分开的,实际上我们需要6个实际的参数)再放到自己定义的函数里面,作为默认参数就可以了。

注:这里不是每一个事件都一样,如EndOverlap,我们打开之后如下,选择只有四个参数的

至此委托就已经介绍完毕,如果还是看不懂这个过程,可以查看本文第二个参考链接的一位Up主的视频。
参考链接:
Delegates and Lamba Functions in Unreal Engine | 虚幻引擎5.0文档
【ue4_C++】用委托(代理)实现开门、开灯效果_虚幻引擎_C++_蓝图_哔哩哔哩_bilibili
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir