本节内容继续上一节教程的内容(如果没有看过前面的教程,请前往学习),不会讲太难的新东西,而是继续探究技能标签(Abiilty Tags)的内容。先来一道开胃菜。
第1.1步:
将上一次的召唤冰龙中的CancelAbilitiesWithTags清空,表示这个技能不会打断任何其他技能。在“阻塞技能列表”BlockAbilitiesWithTags中配置Magic.Fire。
第1.2步:冰龙的激活逻辑修改为下图所示,表示它也是耗时的技能。
第1.3步:运行,先释放烈焰之鸟后释放冰龙,从打印中可以看出:BlockAbilitesWithTags不会打断烈焰之鸟。
先释放冰龙,后释放烈焰之鸟,从打印看出:烈焰之鸟在冰龙释放的过程中不能释放。
(这个图可能说明不了什么,请您自己动手实验看看)
总结:某个Ability(A)中的BlockAbilitesWithTags(B)规定了“当A释放时,B类技能无法释放”。
下一组探究实验(技能Buff和技能前置状态):
第2.1步:在ProjectSettings-GameplayTags中新加Buff.Fire这个Tag(其它的Buff我随意添上了,不要紧)。
规定:在我这里的例子中,Buff是给英雄(Character)用的,虽然结构本质上和AbilityTag一样,但是意义上不是AbilityTag。
第2.2步:配置烈焰之鸟的“释放者获得标签列表”(ActivationOwnedTags)中添加Buff.Fire。
烈焰之鸟的激活逻辑不改。
爆炎凤凰的“释放前置标签列表”(ActivationRequiredTags)中添加Buff.Fire,表示爆炎凤凰要求Character具有Buff.Fire标签(从游戏中说就是需要Buff状态)。
第2.3步:在character的myabilities数组中加入爆炎凤凰,并为它绑定释放事件:
第2.4步:保存编译运行。
实验验证:只有在烈焰之鸟释放后,烈焰之鸟使Character具有Buff.Fire标签,爆炎凤凰才能够释放。
延伸知识:
·同样,不做实验地,介绍一个属性:“释放受阻标签列表”ActivationBlockedTags,表示当Character(释放者)具有这些标签时,无法释放这个技能,例子是当具有Buff.Fire标签时,召唤冰龙无法释放。
下一组实验是官方给的一个例子。
第3.1步:声明一个Ability,然后蓝图编辑如下。
第3.2步:概念说明:其中的OwnerActor表示此技能的拥有者(释放者)。
第3.3步:在Character中绑这个Ability(绑在MyAbilities数组上即可,不过为什么绑上去了就可以呢?原因是因为代码里有初始化,请见前面的教程),绑定输入事件,这里不给出图片了。然后编译运行。
第3.4步:效果如下图:
这个例子中的targetdata如何自定义呢?目前还不清楚。
下一个概念是GameplayTasks,写在GameplayAbility中的事件称为GameplayTask,即
接下来是讨论GameplayEffect,在蓝图处建立GameplayEffect:
查看其中的属性:
先贴一段理论介绍(本文源于https://wiki.unrealengine.com/GameplayAbilities_and_You#GameplayTasks):
Notable Variables
显著的变量
Due to the unusual nature of Gameplay Effect blueprint classes, most of their variables are either simple values, other direct class references or just tags. There are too many to list and after explaining how abilities and their tags work, it should be fairly self-explanatory what most tags are used for, or do. It should however be noted that Gameplay Effects have 3 containers for each type of tag, one that is not directly editable, one that describes tags added on top of tags potentially owned from a parent and tags that are removed from a potential parent. Basically, this tag inheritance setup is one of relatively few reasons why Gameplay Effects are full-fledged UObject classes in the first place. Some of the more notable variables are:
由于游戏效果蓝图类的特殊性质,它们的大部分变量都是简单的值,其他直接的类引用或者仅仅是标记。有太多的东西要列出,在解释了能力和标签的工作原理之后,应该相当清楚地说明大多数标签是用来做什么的,或者是做什么的。但是,应该注意的是,对于每种类型的标签,游戏效果有三个容器,一个不是直接可编辑的,一个是描述标签上添加的标签的标签,这些标签可能是来自一个潜在的父类和标签的。基本上,这个标签继承设置是一个相对较少的原因,为什么游戏效果是一个成熟的UObject类。一些更值得注意的变量是:
Duration Policy: Is the effect instant, does it have a fixed duration, or does it go on infinitely? Do note that instant effects turn modifiers into permanent stat changes, and executions will be triggered immediately.
持续时间策略:效果是即时的,它有固定的持续时间,还是无限延伸?请注意,即时效果会将修改器变成永久性的属性更改,并且会立即触发执行。
Modifiers: Stat changes in all shapes and forms. Whether you want to add a flat amount to a stat, multiply a stat, divide, override with a fixed value or do any of these things in relation to other stats.
修饰词:所有形状和形式的变化。无论你是想要在一个数据中添加一个平量,还是要用一个固定值乘以一个固定值,或者用一个固定值来做这些事情。
Executions: Executions are an interesting case: They are essentially the functions the gameplay effect itself can't have (due to being meant to be as data-only as possible). An Execution takes a GameplayEffectExecutionCalculation as parameter, a class that is set up to define attributes to capture from both target and source, and to do things with them that would be considered too complex with modifiers alone. They are more or less meant to do as they please, however they cannot listen to events and such like abilities can do and pretty much only run in fixed, predefined intervals on timed GameplayEffects (and optionally once on application), or immediately on application in the case of instant GameplayEffects. They're your go-to for complex damage calculation and the likes. More on that later.
执行:执行是一个有趣的例子:它们本质上是游戏效果本身不具备的功能(由于被认为是尽可能的数据)。执行GameplayEffectExecutionCalculation作为参数,设置定义的类属性捕获目标和源,并与他们做事情,会被认为太复杂修饰符。他们或多或少都是想按他们的意愿去做,但是他们不能去听事件,而且他们也只能在固定的、预先确定的时间间隔上运行游戏效果(或者在应用程序上),或者在即时游戏效果的情况下立即应用。它们是你对复杂的损伤计算和喜好的首选。稍后将进行更详细的讨论。
Stacking: You know how in some games certain buffs/debuffs of one kind can stack on a target? This behaviour is managed here. By default all GameplayEffects of the same type will act and tick down independently (though requesting the amount of stacks of a gameplay effect will usually still show the total amount of effect instances of this type). There are options to make them all go on the same timer, removing one stack each time duration runs out, removing all of them once the timer runs out once, if application of a new stack refreshes the current duration or if there is a cap on stacks. You can get quite creative with these.
堆叠:你知道在一些游戏中,某一种类的缓冲/ debuffs能在目标上叠加吗?这种行为是在这里管理的。默认情况下,相同类型的所有游戏效果都是独立运行的(尽管要求游戏效果的堆栈的数量通常仍然显示这种类型的效果实例的总数)。有一些选项可以让它们都在相同的计时器上,每次删除一个堆栈的时间持续时间,如果一个新堆栈的应用程序刷新当前的持续时间,或者如果在堆栈上有一个上限,那么在计时器运行一次之后删除所有的堆栈。你可以用这些来很有创意。
Overflow: Adding up on stacks, overflow effects are essentially effects that the affected actor will be affected by when the max amount of stacks of this gameplay event has been reached. If you get cold enough you freeze, breathe enough poison gas to get heavily poisoned, whatever, you get it.
溢出:在堆栈上加起来,溢出效应实际上是影响到受影响的参与者将会受到影响,当这个游戏的最大数量的堆栈到达时。如果你变冷了,你会冻死,呼吸足够的毒气来毒死,无论如何,你都会得到它。
Display: You can define GameplayCues to use here. At their most basic, GameplayCues are essentially visual/audible effects that respond to a specialized tag they've been assigned to. It needs to have "GameplayCue" as its parent tag, so an example tag could be "GameplayCue.DoT.Fire". You can call these directly in abilities too. They're a network-friendly way to spawn stuff like particle effects, cosmetic meshes and sound effects to provide your debuffs and skills with some eye candy. How they react to being called by the GameplayEffect/Ability is defined within the GameplayCue itself (there's 4 types of events a GameplayCue will respond to: On Applied (activates when applied), While Active (constantly triggers while active, presumably), Removed (when... well, removed) and Executed (this is interesting: When a GameplayEffect's execute classes run, this will play).
显示:你可以在这里定义游戏提示。在最基本的情况下,游戏提示基本上是视觉/听觉效果,可以对被分配到的特殊标签作出反应。它需要有“GameplayCue”作为它的父标签,所以一个示例标签可以是“GameplayCue.DoT.Fire”。你也可以直接把这些称为能力。它们是一种网络友好的方式来产生像粒子效应、化妆网和音效的东西,来为你的debuffs和技能提供一些eye candy。他们对被称为游戏效应/能力的反应是在游戏提示本身中定义的(游戏中有四种类型的事件:在应用时(激活时),当激活时(大概是激活的时候),被移除(当…好,删除)和执行(这很有趣:当一个游戏效果的执行类运行,这将会播放)。
GrantedAbilities: This has many uses. You may use a buff to temporarily provide an active ability as part of the buff(maybe a fire mage can give someone else a fire ability by igniting one of his allies? Heh, gotta love combat arson), but, more importantly, you can use these for effects that are too specific for modifiers but need to be permanently active in a way effect executions can't. If a gameplay effect is tagged to grant an actor an "OnFire" tag, you may have an ice buff with a passive ice ability granted listen for this event and remove the offending effect, as well as the ice buff itself (GameplayAbilities have a function just to allow them to remove the effect that granted them). Together with modifiers and executions, this allows you to do virtually anything with your effects.
天赋:这有很多用途。你可以用牛子暂时提供一个活跃的能力,作为牛子的一部分(也许一个火法师可以通过点燃他的一个盟友给其他人一个火的能力)。Heh,要热爱战斗的纵火,但是,更重要的是,你可以使用这些效果,对于修饰语来说太具体了,但是需要在一个有效执行的方式中永远保持活跃。如果一个游戏效果是标记授予一个演员一个“OnFire”标签,您可能有一个冰迷一个被动的冰能力授予监听这个事件并删除冒犯效果,以及冰迷本身(GameplayAbilities函数只是为了让他们删除授予他们的效果)。与修改器和执行一起,这使您可以对您的影响做任何事情。
It should be noted that most float values put into are not actually just plain float values, but rather a struct called FScalableFloat. You can use it just like any regular float, but there is an asset pointer to the right of the box where you'd put the float value in. It may confuse you because there are no valid references to use, and there is no option to create a new one. This slot is reserved for a Curve Table, an asset you get by importing a csv, or file with a comparable table file format, into the project.
应该注意的是,大多数浮动值实际上并不是纯浮点值,而是一个称为FScalableFloat的struct。您可以像任何普通的浮点数一样使用它,但是有一个资产指针指向方框的右边,您可以将浮点值放入其中。它可能会使您感到迷惑,因为没有有效的引用,也没有创建新引用的选项。这个槽是为一个曲线表预留的,您可以通过导入一个csv文件或具有可比较的表文件格式的文件进入项目。
笔者的注释,这里的槽是指下图红框内容,使用时请无视此槽。
我稍微更改一下官方提供的GameplayEffect的例子,请随笔者继续探索:
第4.1步【建立一个GameplayEffect】:命名为GE_FireBuff,表示这个GE是火焰加成。
第4.2步【配置这个GE的时长】:双击打开,然后在ClassDefault中配置一下细节:
其中的DurationPolicy选择HasDuration表示有时长限制,Scalable Float表示时长的相乘系数。在Period中配置时长。表示这个GE的长度是2.0*1.0 s的。
第4.3步【配置这个GE的天赋】:在Tags中看到“天赋加成列表”GrantedTags,在红框位置添加Buff.Fire,在黄框部分将会被动地添加(不需要你手动写上去)。
知识点:GrantedTags表示这个GE被施用在的那个角色上将会添加上这个Tag(Buff.Fire)。
延伸知识:你也能够猜到,如果Added栏写的是Buff,那么Removed栏写的是Debuff(消除某种Buff)。
理念强调:GameplayEffect是不写事件的,它仅仅是一个数据储存结构!
第4.4步【建立一个Ability】:命名为Abi_UseGEFire,然后写上逻辑,其中重要的节点是ApplyGameplayEffectToOwner,表示施用这个GE给能力使用者。
第4.5步:请在Character中配置输入事件,并且在MyAbilities数组上绑定这个Abi_UseGEFire,此处略图。
第4.6步:运行。
实验a:先尝试释放爆炎凤凰,发现没有释放成功,因为人物没有FireBuff(还记得吗?前面需要释放烈焰之鸟,使人物得到FireBuff之后才能够释放爆炎凤凰),施用Abi_UseGEFire之后,再释放爆炎凤凰,是成功的。过了2s之后,没有办法释放烈焰之鸟。
实验b:将上面的scalable float更改为3,0,0.1,1000等数字查看一下效果,发现有点奇怪,好像不是相乘系数的意义。
实验c:将上面的hasduration更改为instant,发现根本没有办法释放爆炎凤凰。
实验d:将上面的hasduration更改为infinite,发现一直都可以释放爆炎凤凰。
实验e:将上面的Added更改为Removed处填写,然后释放烈焰之鸟,之后释放Abi_UseGEFire(此时是Debuff效果),然后释放爆炎凤凰,发现爆炎凤凰还是能够释放出来(期望应该是不释放的,实验发现,这里对removed有误会,或者是有bug)。
下一组实验是Cooldown冷却(也就是CD)。
第5.1步:在GameplayTags面板中添加一个Tag称为CD.Lieyanzhiniao
第5.2步:添加一个GameplayEffect,称为CD_Lieyanzhiniao,你可以惊讶地发现,原来CD也是用GameplayEffect来实现的。
第5.3步:在CD_Lieyanzhiniao中配置Added标签为CD.Lieyanzhiniao,有没有很惊讶,因为这里的天赋标签竟然能够也是CD的实现位置。
第5.4步:在CD_Lieyanzhiniao中配置CD的时长,这里有两个很令人困惑的数字,笔者发现更改上面的会有效果,建议两个数字都写成一样的。这里写10表示10s中的冷却时间。
第5.5步:在烈焰之鸟的Ability中更改:
其中白色框框里面修改了“受阻标签列表”,表示当人物具有CD.Lieyanzhiniao标签的时候,此技能无法激活。
黄色框框是最重要的一个知识点了,CooldownGE规定了当此Ability被提交(commit ability)时,此GameplayEffect会被施用。在烈焰之鸟中添加如下一个CommitAbility的节点:
让我们再来理清一下思路:
CD_Lieyanzhiniao(本质是GameplayEffect)规定了在施用时赋予给人物的便签(CD.Lieyanzhiniao的标签),施用烈焰之鸟时,立即提交Ability,然后烈焰之鸟中规定的CooldownGameplayEffect就会施用,使得人物得到CD.Lieyanzhiniao,然而Ability烈焰之鸟中受阻列表规定了CD.Lieyanzhiniao,所以烈焰之鸟将会在10s之内无法再次使用。
编译运行,实验结果正是如此。让我们看看其描述:
下一节我们继续学习属性集AttributeSet。原创声明:本文系小江村儿的文杰原创,若有参考的资料必在本文中给出。
——小江村儿的文杰 zouwj5@qq.com