虚幻5-内容示例-蓝图通信地图 详解(UE5-ContentExample ...

2

主题

7

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2023-1-19 09:25:29 | 显示全部楼层
文章很长。
先把官方的三个地图分区名字写出来,建议还是都研究一遍,过不去就看一下我的研究过程。由于我是新手,所以基本所有的坑都会踩到,你可以看一下你踩的坑是不是和我一样。
研究这张图我目前已经花了半天天,约9个小时
//“()”代表我花了一段时间研究






每次做小游戏,都卡在不知道怎么和其他蓝图互通上面了,必须要搞定这张地图!
点击示例当中的“?”,可以查看官方文档,但里面是404.我倾向于官方没有写出来,因为搜遍google也找不到文档。只有部分的示例地图有文档,写的也不怎么全,自己动脑子吧。
————————
1.1Basic communication with a target blueprint
.功能很简单,就是靠近按钮的时候;远离按钮一定距离后,关灯。
(1)先看看灯。
……经过长时间的查找,我已经迷糊了。我开始查找文档资料了。
如何使用蓝图通信
查了很多链接,上面这个链接是讲解的最清楚的。直接蓝图通信,关键在于:定义一个变量,设为公有,然后用吸管选择目标蓝图类
我是一个开关,我想打开我面前的灯。但是我按了半天,没有反应,怎么办?我(开关)设置一个变量,类型是“灯“,然后在主面板上,用吸管,点一下我要控制的那个灯。然后,就可以在蓝图里面写代码,控制那个灯了。
公共变量,左边变量的小眼睛打开了,右边InstanceEditable的对勾也就打开了。


如何记忆“直接蓝图通信”?
关键在于,我(开关)没办法直接调用灯。我必须先创建一个变量,变量类型,就选那个灯(父类?),然后主界面吸管选择我具体要开哪个灯。然后我就可以在开关里面写蓝图了。
开关里面,首先把变量(灯)拖出来,然后添加灯里面的事件、函数,都是可以的了。想对灯做什么都可以。



实验1

但是最好不这么做,而是把想对灯做的事情,封装成一个事件,写在“谁能控制我(actor0)”里面,然后通过call Function来调用这件事。
。。。。。
再做个实验2玩一下:如果很多个actor0_0,_1,_2,_3,都想和actor_灯,通信。那么我可以建立一个actor0的父类,点吸管选择灯,是不是子类就不用每一个都点一下灯了?也就是说,1v1的通信(我vs灯),可以变成(N个我)vs灯。试一下能不能做到。
结果是不能。
原因在于,public变量,只能手动在主视口修改。修改的实例,而不是类。所以,不能通过父类--子类的方法,节省自己的繁琐操作。



可以看到,父类选中了灯,子类也还是none

、、、、、
基本理解了直接蓝图通信(1v1),但这样做的话。创建变量还好说,吸管选取这个就太扯了。
总结:1.1的核心是:创建public变量+吸管选取。

1.2 Blueprint communication via actor casting
比1.1稍微复杂一点点。
我靠近开关,开关启动,于是电池向上跑,接触到灯的时候,灯打开;我离开开关,开关关闭,电池向下走,灯关闭。
这里面,一共有我,开关,电池,灯,四个物体。
      //偏个题:动态材质我还不是很懂。先在构造函数里创建了一个动态材质。然后在图表当中设置这个材质,用的是【set scalar parameter value】这个节点。我将节点改为0.5,颜色是中间,改为12,颜色变亮,改为1111,颜色变得巨亮——动态材质实例,这个还需要再学习一下。
A1:我的逻辑:可以移动
A2:开关的逻辑,有一个胶囊体碰撞,当我过去overlap的时候,触发battery的移动事件。开关与battery通过public变量+吸管的方法连接(上一段的直接蓝图通信)
A3:battery的逻辑:被开关触发事件之后,向上移动和旋转半圈。
battery这里,有两个public变量,一个是选择自己的mesh,没什么可说的;一个是电量。改到9999,碰到灯的一瞬间,我眼睛被屏幕晃瞎了!这蓝图通信……但是我没有看到这东西和灯是怎么通信的,只能看一下灯了。
A4:灯的逻辑:
又是一大坨代码……
这次相当清晰,一秒钟看懂(可能是1-3分钟)
模块1:通信
模块2:设置变化曲线
模块3:把变化曲线设置到intensity和light上面。
首先使用碰撞【OnComponentBeginOverlap】,通过other Actor这个蓝色的节点,就能找到“我到底碰到了哪个玩意?”,然后【cast to battery】,就可以调取里面的数据了(听说cast to主要是确认一下,和【is valid】功能差不多,保险作用),然后调取electricity Value的数据,使用。
首先测试一下,去掉cast to,能不能用呢?
结论是不能:看来,我必须通过cast to来确认我碰到的东西是battery,然后才能调用battery里面的数据。
再做一个测试:关于trigger:


这个trigger挂在mesh的下面比较好。这样,我就可以在构造函数当中更换Mesh,而trigger一直在Mesh的中心点——可能也有不方便的地方?

总结一下第二种蓝图通信方法:核心是cast to。
。。。。。。。。。。。。。。。
好,思考一下这两种通信方式:
显然,官方的建议是:当两个物体能碰上的时候,使用cast to来通信。不能碰上,又想隔空通信,再使用吸管+公开变量。
第二个例子里面:
我()开关()电池()灯
通信方法是:我(碰撞)开关(吸管)电池(碰撞)灯。
那么,我碰撞开关,和电池碰撞灯,有什么区别呢?
我碰撞开关,没有检测otherActor,也就是说,随便一个物体在开关周围,开关就会动了?赶紧测试一下。
测试结果:错误。放别的物体,有碰撞,但开关不动。怎么回事呢?
会不会是因为在碰撞当中,只和pawn互动呢?
果然如此:



右边的设置,除了pawn,都是忽略

我再放一个pawn类型的actor过去测试一下看看。
试了一会,不能让我创建的物体碰到这个开关。我需要单独找个关卡测试一下。以前就在碰撞这里没搞明白,再来吧。这地方不能马虎。得花时间。
()
在自己创建的新关卡里,设置generate ovelap event,以及碰撞检测类型之后,是可以的。但为什么在示例关卡当中,不行呢?
()
先放弃了——因为在自己测试的关卡里面,碰撞方面没啥问题。可能是这示例内容的关卡的一些我不知道的设置吧。
好,回头再看一下两种蓝图通信的方式:
直接通信,空对空,使用吸管。我想让灯亮起来,我就用吸管,并在我自己这里创建一个变量。
碰撞通信,可以使用cast to。我碰到灯,灯不但自己写一个变量的函数,还要写一个碰撞的函数,并在碰撞节点那里,调用我身上的(electricity Value),来改变自己的状态。
也可以反过来,我cast to灯,那就是我借灯身上的函数,来改变自己。
那么,第一种吸管的方式,我可以通过吸管,来改变自己的数据吗?我试试看。我可以做到。
总结:
我想从别人身上获取数据,改变我自己。可以用吸管吸取别人,然后get其数据,改变自己;也可以碰撞别人,cast to别人,获得数据,改变自己。结果是改变自己,比如在自己身上写一样代码print hello。
我想从直接控制别人,让别人做某事:可以用吸管吸取别人,在别人身上创建一个自定义事件,在自己身上引用别人的变量,call function,让别人做那个自定义事件(和上面的逻辑是一样的:谁变了,变的内容在谁身上写。
cast to的方法,控制别人,就比较有趣了:
我在自己的trigger身上,cast to对方,改变对方,可以。我在自己的trigger身上,cast to对方,拿到对方数据,用这个数据改变自己,可以。
上一段的总结:改变两方中的任何一方,通信都可以做到。
。。。。。。。
嗯,我确认上面的一大段自己都很蠢。官方给了不同蓝图的用途,参考这里就行了:
蓝图通信用法
我继续学后面的蓝图通信,然后放在一起总结。

__________________________________________
1.3 Blueprint communication via actor casting to child Blurprint.
哇哦!果然在这里有例子可以专门研究父子类的casting蓝图通信功能,之前的坑现在补上了,赶紧看一下。
()
(1)父类和子类的区别,看名字没用(名字是自己起的),看路径:如果最后一个字是文件夹(比如BlurPrint),就是父类,如果是http://xxx.xxx,那就是妥妥的子类了.
(2)这1.3有:三个开关,三个电池,三个灯。
灯是一样的;开关是一样的;三个电池,一个父类,两个子类。
这和1.2似乎一样的啊。只要在public那里,设置一下电量,就能达到同一个父类,不同效果的影响子蓝图了。真的是这样的吗?我来看一下电池子蓝图的代码。
和设想的一样。两个子蓝图里面啥也没有,全靠父类蓝图的public变量,在public面板上面修改值。
1.3很简单。过了。
————————————————————

1.4 communication with all actors of a specific class.
()
这关卡功能有点意思:一个开关控制6个灯。灯和灯闪烁的有快有慢。所有灯都是一个类,没有父类子类关系。也没有public变量。
()
果然如我所料,使用了经典的【get all actors of class】+【ForEachLoop】组合。
有两个问题
问题(1)【GetAllActorsOfClass】节点里面,dropdown菜单的类名,和灯的名字不一样
问题(2)这次是开关castTo灯,而不是之前的,灯castTo开关,区别在哪?
先研究第一个问题
()



为什么多了一个.xxxxxxx_C呢?不理解

但似乎也没有别的好选择了。改一下灯的名字,然后看看这个下拉菜单(dropdown)里面会不会变。
()



不知道_C哪来的,也不影响使用,放一边吧

问题(1)解决。继续考虑问题(2):在开关的地方castTo和在灯的地方castTo有什么区别?
()
想通了,显然不复杂:
如果我(玩家pawn)想让很多灯亮,有的灯亮度2000,有的灯亮度5000,显然,这不同点是在灯自己身上。所以,开关是一个,但属性有许多(本例是随机),所以要一个开关,castTo很多灯。
而在上一个例子当中。如果我(我是灯)想接通不同的电池,那么我要获取那些电池里面的数据,自然用的是从灯castTo电池。
所以,总结下来,就是castTo适用于,1vsN的情况,从1castTo多。
()


新出现的【SetPlayRate】节点,设置timeline用的,没啥稀奇。过了
——————————————————————————
——————————————————————————
第二部分:大致看了一下,似乎不复杂,一个一个来。
2.1 Using an event dispatcher function to call an event in the level Blurprint.
.事件分发器(event dispatcher)没用过,看一下咋回事。
()
我搜到下面这个链接,讲的还算可以:
事件分发器
大致理解一下事件分发器:“开灯这件事”可以简化为下面三个步骤
我去碰开关——开关找到事件分发器——事件分发器找到灯。(没了)
似乎不复杂。
两个信息:(1)事件分发器是一种委托。那么委托是啥?(2)事件分发器还可以找到除了灯之外的东西,比如桌子椅子之类的?
继续看。
()
下面这个链接,比刚才那个链接,更通俗易懂。上面那个链接很破——Epic最大的错误,就是舍不得删掉那些写了还不如没写的文档!舍不掉删掉那些有的还不如没有的功能!纯让我浪费时间。
事件分发器/委托快速入门指南
跟着这个教程,从第17步开始,就需要注意了(前面和开关门的教程一样)。
注意(小小坑):这个教程4.1,爆炸声的自动播放,两个都要禁用,而且是先禁用父级再禁用子级才能都禁用,都禁用完成之后,再拖进关卡中测试。点击播放之后没爆炸声才算成功。
()
跟着教程做一遍,确实能让事件分发器成功运行。好,现在我来理解一下其中的原理:
()
上面链接当中的官方教程原理(先暂时从“示例内容”当中跳出来)并不复杂:
场景当中有我(小白人)+一个盒体触发器+3个爆炸声and旋转门。要实现的功能是:只要我走到那个盒体触发器,三个爆炸声会响,旋转门也会响。
PS:castTo似乎可以做到这一点,但实际不方便,因为那必须都是一个类。这个例子当中,有爆炸声和旋转门,是不同的父类,所以才要用到事件分发器,可以给不同的东西下通知。
具体做法是这样的:
(1)在盒体触发器中,创建event Dispatcher(显然,事件分发器是一个全局的东西,所有其他变量,包括蓝图变量都可以用这个东西。
(2)旋转门和爆炸声Audio都可以绑定到这个事件分发器。具体做法是:



旋转门,还是要用吸管吸取一下盒体触发器

或者:



爆炸声

也就是说,【eventBegin】——【BindEventToOnBossDied】——自定义事件名【BossDied】——我要干的事情【Activate】启用爆炸声。
这里,自定义事件是任意起名的,反正只要绑定到了OnBossDied这个事件分发器,就可以了。
。。。。
先睡觉,明天继续做,把蓝图通信这一块要搞明白,才能开始去研究“蓝图输入Map”
。。。。。。。。。。。。。。。。。。。。
一觉醒来:继续做。我发现,昨天显然走了弯路。因为下面这个链接:
https://docs.unrealengine.com/5.1/zh-CN/how-to-use-blueprint-communications-in-unreal-engine/
介绍了我想要做的事情,发射一颗子弹,给这个子弹编号,然后我按键,子弹就转向,其实直接蓝图通信可以实现,啊啊啊。我这次的做法是:在虚幻文档中,搜索“蓝图通信”,然后把所有相关的文档都找出来。昨天找出来了,但我觉得文档太散乱,还是去研究map去了,实际上,还是读一遍文档最好,哪怕是粗略的扫一遍也好。
总结:一定要先大概扫一遍所有的已有资源,目标不是直接学习,不是直接学习!而是确定哪些资源是信息密度高的资源,哪些是低的,后期专注学习的时候,我将抛弃绝大多数低密度资源,直接专注的学习高密度资源
。。。。。。。。。。
哇哦,这一部分:使用这种方法,不用使用吸管!不用使用吸管!




这一部分,让我可以生成子弹,并且实时修改子弹的速度。我的问题在于:我很难理解“把子弹当成一个变量”,去操作。我试试能不能把子弹存为一个数组。显然肯定是可以的,所以我需要补齐关于数组的基本操作。我会的是c++里面操作数组的方式,我看一下蓝图的。
()
我有点着急了,我先看看关于数组的基本节点什么的都是怎么回事吧。
()
【SetArrayElem】前面连接【ForEachLoop】就可以把已经有的元素存进数组当中,读取也简单,还是用【ForEachLoop】。注意把size to fit勾上就行了。对应C++里面用指针指定数组的第一个变量的地址?



已经创建好的数组,已经创建了3个元素



新的数组,没有元素,但√上了size to fit,所以无妨

()
我好像白痴一样……
【add】可以添加元素。【get】可以取得元素。
【make array】可以动态创建数组。
那个进阶进阶的塔防教程里面,好像有用add添加数组的方法?别着急,先学学基础。
()
尝试成功!!!
我已经可以受控制的发射子弹,把子弹存储为变量,并且通过子弹数组的下标index,借助【ForEachLoop】循环,控制每一个子弹的行为了!


哈哈哈哈!这就是我学蓝图通信最开始的目标呀!
【spawn actor】+【add】+【actor变量数组】+【forEachLoop】+【set速度】
()
好继续,我现在已经可以设置每一颗子弹了,那我现在能设置每一颗子弹,和不同的敌人之间的通信吗?(只要通信成功,我就可以同时设置子弹和敌人)
()
更新了一下自己的计划,然后重新回来。后续计划,三步走:
(1)先把地图看完(为主)
(2)把文档看完(为主)
(3)设想将这些功能应用到我的塔防游戏当中的小应用(当然不是直接全写完)(为主)
现在做第一步,重新实现一下事件分发器2.1。看看我能不能自己实现2.1实例当中的功能。官方给出的说明是这样的:
a button Blueprint toggling a lightBulb Blueprint on and off via an Event Dispatcher Function.
The button call the event dispatcher, which fires the event in the level Blueprint to toggle the light on and off.
这里实际上有五个部分。我——()开关——()事件分发器——()关卡蓝图——()灯
我——(collision)开关——(创建全局的)事件分发器——(call)关卡蓝图——(创建一个引用,定义到灯上面的自定义事件)灯
看起来还是挺简单的,自己创建一个关卡,实现一下这个功能。
()
好像2.1是困难的(有关卡蓝图,还有另外一个例子),实现2.2,2.3是简单的?我先看看2.2和2.3的代码。
()
嗯,没错。2.2的事例和我在上面链接中做的事例是一样的,简单。我来看一下2.3,如果2.3困难,那我就先尝试做一下2.2。
()
2.3。
2.3并不是让按钮去通知生成炸弹,而是炸弹生成之后,爆炸,爆炸之后,再回来通知按钮:你可以再次释放炸弹了。
(1)事件分发器写在哪个地方,就在哪里写【call 事件分发器】这个节点(我发出消息了)你们谁跟这个事件分发器绑定的,就来接收一下吧。
()
嗯,大致看明白2.3了。写的很细腻的循环操作,还是比2.1简单。2.1有关卡蓝图参与,不懂。那么学习的顺序就是2.2——2.3——2.1。
好,现在我开始尝试复制2.2。
()
好,思考一下2.2的基本功能。我是一个人。我触发一个按钮,按钮创建一个分发器,call这个分发器,物体绑定分发器到自定义事件,自定义事件驱动旋转。就这么一个过程。
()
在2.2,也就是事件分发器的基础版本当中:还是必须使用创建变量——设置变量类型为(创建了分发器的)变量——public——回到主视口——吸管吸取要绑定的那个具体的实例。
这么一个过程。
我可以创建多个物体,在主视口当中,吸管吸取要绑定的那个事件分发器。
好,2.2过了。看2.3
()
2.3,生成一个炸弹,炸弹身上有事件分发器,爆炸之后,通知我,我可以开启下一次触碰事件。
()
这里有点意思啊,生成的东西,怎么通知按钮呢?我先不用他给出的方法,我用上面给出的spawn+直接通信的方法。
()
明白了。重点在于,谁是信息的发出方,谁是信息的接受方。接受方,需要提前拿到一个信息发出方的reference。在本例当中,炸弹反过来发送消息给按钮。按钮怎么才能先接受到炸弹的信息呢?只能是在spawn的时候,用那个return value这个键值,拿到炸弹的引用!
也就是说,关键在于,如何拿到引用。用【spawn actor】可以拿到这个引用,用吸管可以拿到引用。
()
例子已经解决了。但是,如果我想做这样一个功能:
尚未生出出来的子弹,如何在碰到敌人之后,给敌人一个30滴血量的damage,并且不用碰撞,而是用事件分发器,我该怎么做呢?子弹已经可以和自己通信了(用spawn拿到子弹的引用)
用吸管呢?不行,因为敌人也没有生成呢。
所以,我的问题是这样的:尚未生成的子弹,如何联系到尚未生成的敌人?——不知道。我先回去看看2.1吧。学完接口以后,重新回来思考这些具体的问题,并代码敲出实例。
看2.1
()
事件分发器+关卡蓝图
在文档的这里:我找到了一个带关卡蓝图的事件分发器的说明,跟着做一遍:
如何使用蓝图通信
()
这个跟着做有bug,做不了。
我能用【get all actor】代替吸管吗?竟然可以!
那我就不用每次都吸管啦!
【get All actor of class】神器!,代替吸管。
2.1 关卡蓝图,可以像普通蓝图一样。只要获得发信者的引用,即可。
。。。。。。。。。。。
下一个问题:我发现:发信者和接受者,是一个比较好的分类方法。发生事件(其实谁都可以发生事件),关键在于,谁发信,谁接受。
根据发信者和接受者的逻辑,我重新思考【直接蓝图通信】【castTo蓝图通信】【事件分发器】三者。
在直接蓝图通信当中,按钮获得了一个灯的引用,并且把消息发送给灯。让灯亮起来。
发信者是按钮,收信者是灯。发信者使用吸管,使用public变量,吸取灯。
。。。
在castTo通信当中呢?(1.2)
我碰撞到了按钮,但我没有事件。
按钮身上有事件,按钮发出一个消息(有一个“玩家”触碰到了我(按钮)),把这个消息发送给电池(直接蓝图通信方式),电池移动,碰撞到了灯,但电池身上没有事件。
灯身上有碰撞,并且希望从电池身上获取一个消息——这个挺有意思的,也就是说。灯是主动的一方,但不是主动发射消息,而是主动的想要接受消息。我,要求你,给我你身上的信息——这种情况用castTo。
。。。
事件分发器呢?
很明显,发信者不关心谁收到没收到,反正我发信了。我直接【call 事件】
。。。。。
嗯,总结的差不多了。继续看蓝图接口吧。
——————————————————————
()
3.1——3.4看起来最复杂,但好像是最简单的实现方式?我具体自己用一下呢?我找到上面的那个用途网页,然后想想每一种用法。
()
接口创建好以后,任何一个类,都可以发送消息,在自己的面板里面,调出蓝图接口函数。但是想要和别的蓝图通信,还是必须获得那个灯的引用,门的引用,火花效果的引用。创建数组保存他们,创建变量保存他们。
在这里,比如说,我是那个门。我添加了接口,谁都可以让我打开。只要他提前对我加了引用。也就是说,引用方法是关键。我现在有三种引用方法
(1)get all actor of class+ForEachLoop
其实还有get all actor of class with tag/interface。所以,获取变量也不难!
(2)吸管
(3)spawn引脚引出来。
。。。。。。。。。
那么,如果我想要实现,检测一个圆周里面的敌人,我只需要再学习一个节点,那就是【sphereTraceByChannel】——学习这个节点,让我有点迷糊,这个是检测碰撞的吗?
以及,我能不能开始总结我学到的通信技术了?
()
。。。。。。。。。。。
总结:懂了。也就是说,无论哪种通信方式,都需要有一个引用。吸管吸取,get actor of class byXXX,从spawn的引脚引出,都需要有一个变量,来存储引用的数据。只要拿到了,就可以互相通信。所以,其实直接蓝图通信、castTo、蓝图接口、事件分发器,这些东西,都是更上层的东西。只要找到了那个我需要的类,那么其他内容就简单了。哎。我研究半天,方向还是错了。没有C++基础啊!
。。。。。。。。。。。
我现在可以尝试构建一下我的那个塔防的场景了,我有两个思路
1:直接做,做到做不动的时候,看那个进阶进阶教程
2:看那个进阶进阶教程,看到能跑通的时候,再开始做我那个塔防的原型。
我选择(1)
。。。。。。。。。。。。。
附查找资料的几个链接:
如何使用蓝图通信
接口快速入门指南
Actor通信
【UE4蓝图初学节点整合】01_宗浩多捞的博客-CSDN博客_ue4蓝图节点大全
UE4蓝图通信-蓝图接口_宗浩多捞的博客-CSDN博客_蓝图接口
事件分发器?
https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/ActorCommunication/EventDispatcherQuickStart/
蓝图通信用法
回复

举报 使用道具

您需要登录后才可以回帖 登录 | 立即注册
快速回复 返回顶部 返回列表