GAS Base
前言
- 4.27好多bug啊, 例如GA的Trigger Source的问题
- 使用版本: 5.2.1, 注意版本问题GAS版本之间是有差异的, 4.27和5.2.1差异就很大
- 本文旨在描述GE/GA/GC的细节面板, 使用时可参考,不是入门教程
- 大多都亲自试验过, 能保证正确性(参考链接里内容可能有错误,我进行二次勘误了)
- 真的很想吐槽有些文章,照着注释(GAS的注释也一塌糊涂)想当然解释,不亲自实验一下,误人子弟
Gameplay Ability
1. Tag
- Ability Tags:该GA的标签。
- Cancel Abilities with Tag:激活该GA时,打断其他拥有所选标签的GA。
- Block Abilities with Tag:激活该GA时,阻止激活拥有所选标签的GA(已经激活的不会被中断)。
- Activation Owned Tags:激活该GA时,赋予ASC所选GA。
- Activation Required Tags:激活GA时,ASC需要的标签。
- Activation Blocked Tags:激活GA时,ASC不能有的标签。
- Source Required Tags:激活GA时,Source需要的标签。
系统如何看待"Source Tags"并不是很明显,因为没有任何地方对它做出解释,不过你可以使用GameplayEvents特性,携带Payload来激活技能。GameplayEvent能够传递一个结构体,里面有一个InstigatorTags,可以用作Source Required和Source Blocked Tag的检测。当Payload包含所有指定的Tag,技能允许被激活。
- Source Blocked Tags:激活GA时,Source不能有的标签。
- Target Required Tags:激活GA时,Target 需要的标签。
同样的规则,只不过这里使用Payload结构体中的TargetTags。InstigatorTags应该使用技能所有者和触发者(通常是Character类)的描述性Tag来填充,然后TargetTags应该使用技能攻击目标的相关信息来填充。代码并没有强制你如何填充GameplayEvent数据中的Tag容器,你可以想咋整就咋整,这是真的。
- Target Blocked Tags:激活GA时,Target 不能有的标签。
2. Input
- Replicate Input Directly: 设为true, Client会一直向Server同步输入的按下(Press)和松开(Release)事件。Epic不建议使用该选项, 推荐使用AbiliyTask的
Wait Input Release
和Wait Input Press
触发事件:
/** Direct Input state replication. These will be called if bReplicateInputDirectly is true on the ability and is generally not a good thing to use. (Instead, prefer to use Generic Replicated Events). */
UFUNCTION(Server, reliable, WithValidation)
void UAbilitySystemComponent::ServerSetInputPressed(FGameplayAbilitySpecHandle AbilityHandle);
UFUNCTION(Server, reliable, WithValidation)
void UAbilitySystemComponent::ServerSetInputReleased(FGameplayAbilitySpecHandle AbilityHandle);
3. Advanced
- Replication Policy: 不要使用该选项. 这个名字会误导你并且你并不需要它.
GameplayAbilitySpec
默认会从服务端向所属(Owning)客户端同步, 上文提到过, GameplayAbility不会运行在 Simulated Proxy 上, 其使用 AbilityTask 和 GameplayCue 来同步或者RPC视觉变化到 Simulated Proxy. Epic的Dave Ratti已经表明要在未来移除该选项的意愿. - Instancing Policy: GameplayAbility的实例化策略决定了当GameplayAbility激活时是否和如何实例化.
- Non-Instanced: GameplayAbility操作其ClassDefaultObject, 没有实例创建.
- 性能最好,但是不能存储状态,不能有动态变量和AbilityTask
- Instanced Per Execution: 每有一个GameplayAbility激活, 就有一个新的GameplayAbility实例创建,同一种类型的GA会被重复执行
- 性能较差,默认情况。
- Instanced Per Actor: 每个ASC只能有一个在激活之间复用的GameplayAbility实例(首个Activate的GA未End时,重复的GA会被忽略)
- 最常使用的策略,实例GA不会轻易被销毁
- Non-Instanced: GameplayAbility操作其ClassDefaultObject, 没有实例创建.
- Server Respects Remote Ability Cancellation: 如果Client的GameplayAbility由于玩家取消或者自然完成时, 就会强制它的Server版本结束而不管其是否完成。反之一样
- Retrigger Instanced Ability: 仅当Instancing Policy为Instanced Per Actor起作用, 若为true,首个Activate的GA未End时,重复的GA会End(不是Cancel)正在执行的GA然后重新Activate
- Net Execution Policy: GameplayAbility的网络执行策略(Net Execution Policy)决定了谁该以什么顺序运行该GameplayAbility
- Local Only: GA只运行在所属(Owning)客户端. 这对那些只需做本地视觉变化的Ability很有用. 单人游戏应该使用Server Only
- Local Predicted: GA首先在所属(Owning)客户端激活, 之后在服务端激活. 服务端版本会纠正客户端预测的所有不正确的地方
- Server Only: GA只运行在服务端. 被动GameplayAbility一般是Server Only. 单人游戏应该使用该项.
- Server Initiated: GA首先在服务端激活, 之后在所属(Owning)客户端激活.
- Net Security Policy: GameplayAbility的网络安全策略决定了Ability应该在网络的何处执行. 它为尝试执行限制Ability的客户端提供了保护.
- ClientOrServer: 没有安全需求. 客户端或服务端可以自由地触发该Ability的执行和终止.
- ServerOnlyExecution: 客户端对该Ability请求的执行会被服务端忽略, 但客户端仍可以请求服务端取消或结束该Ability.
- ServerOnlyTermination: 客户端对该Ability请求的取消或结束会被服务端忽略, 但客户端仍可以请求执行该Ability.
- ServerOnly: 服务端控制该Ability的执行和终止, 客户端的任何请求都会被忽略.
4. Costs
内部判断逻辑: CurrentValue + CostValue < 0.f
注意:
- 必须要显式调用
CommitAbility
之后才能提交Cost, 若不Commit但是一次性Cost导致 CurrentValue<0.f 还是会导致技能放不出来 - 用的CurrentValue判断, 理论上GE是否设置Period都可以用
5. Triggers
Triggers Source:
- Gameplay Event: 当Owner收到一个带有Tag的Gameplay Event(不是Gameplay Effect的GE!)时调用一次GA,此时Owner不会拥有对应的Tag。
- Owned Tag Added: 当Owner获取对应Tag的时候调用一次GA,失去Tag不会Remove GA,后续可以通过其它方式调用
- Owned Tag Present: 当Owner获取对应Tag的时候调用一次GA,失去Tag会Remove GA,GA若执行未完成会被Cancel
6. Cooldowns
注意事项:
- GE的GrantedTags设置Tag后才能起作用。
- 本质上通过Tag来限制, 通过其它方式为ASC添加对应的Tag后, GA也不能释放。Cooldowns GE只是确定了GA的Cooldown Tag罢了
Gameplay Effect
1. GameplayEffect
Use Curve Table: 根据GE的 Level 去查询Curve Table得到对应值,有乘数则会与其相乘。GE Level = 0 相当于 1
Magnitude Calculation Type:
- Scalable Float: 指定浮点数
- Attribute Based: 捕获Attribute再加以运算
- 计算规则
Coefficient * (PreMultiplyAdditiveValue + AttributeToCapture) + PostMultiplyAdditiveValue = Magnitude
- Backing Attribute:
- Attribute Source: Target或者Source,GE的作用者和发出者
- Snapshot:Snapshotting意味着当GameplayEffectSpec创建时捕获该Attribute, 而No Snapshotting意味着当GameplayEffectSpec应用时捕获该Attribute.
- Attribute Curve: 用捕获的Attribute值去查询Curve,然后放进公式计算,而不是直接使用
- Attribute Calculation Type:
- Attribute Magnitude: 捕获Attribute的 CurrentValue
- Attribute Base Value: 捕获Attribute的 BaseValue
- Attribute Bonus Magnitude: 捕获Attribute的 CurrentValue-BaseValue
- Source Tag Filter: 源码注释如下
Filter to use on source tags; If specified, only modifiers applied with all of these tags will factor into the calculation
- 实际测试并不起作用, 观察源码逻辑似乎也没有使用这个参数实际对这次Magnitude值产生什么影响(可能是预留参数?等我研究清楚再补上)
- Target Tag Filter:
Filter to use on target tags; If specified, only modifiers applied with all of these tags will factor into the calculation
- 计算规则
- Custom Calculation Class: GameplayModMagnitudeCalculation Class,自定义运算得出返回值作为Magnitude。可参考 自定义Calculation Class
// 重载函数 virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;
- 得到返回值后可以在GE中进一步修改,计算规则
Coefficient * (PreMultiplyAdditiveValue + ReturnMagnitude) + PostMultiplyAdditiveValue = Magnitude
- Final Lookup Curve: 用上述公式计算得到的Magnitude去查询Curve作为最终的Magnitude
- 得到返回值后可以在GE中进一步修改,计算规则
- Set by Caller: 从Caller中得到Magnitude
ASC->MakeOutgoingSpc->AssignSetByCallerMagnitude
1.1 Duration Policy
- Instant: 立即启用,用以改变属性的BaseValue。因为是瞬时的效应,不应该用来添加GameplayTags
- Duration: 拥有持续时间,若无Period修改的是属性的CurrentValue, 有则每次执行相当于Instant,修改的是BaseValue。可以添加Gameplay Tags。
- Duration = -1 , 数值不会改变, 相当于Infinite;
- Duration <= 0 , 数值会随时间逐步减少, 但不会中断也相当于Infinite
- 所以请注意, 首次给Duration赋值一定要>0
- Infinite: 持续时间是永久,但可以手动移除。若无Period修改的是属性的CurrentValue, 有则每次执行相当于Instant,修改的是BaseValue。可以添加Gameplay Tags。
1.2 Modifiers
- Attribute: 要作用的Attribute
- Modifier Op: 修改方式
- Add: Attribute += Magnitude
- Multiply: Attribute *= Magnitude
- Divide: Attribute /= Magnitude
- Override: Attribute = Magnitude
- Invalid: 应该没用, 选择这个引擎会触发Assert
- Source Tags: 根据GASDocumentation
SourceTags and TargetTags can be set for each Modifier. They work the same like the Application Tag requirements of a GameplayEffect
- 但似乎我实际应用起来没有对单个Modifier起作用,不知道是不是我的操作方式不对,此处存疑等我弄明白再补上去
- Target Tags:
1.3 Executions
GameplayEffectExecutionCalculation Class, 可参考 自定义Calculation Class
// 重载函数
virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
1.4 Conditional Gameplay Effects
当GE成功Apply(注意是Apply,在不满足Ongoing Tag Requirements的条件下也是可以生效的),会产生附加GE
- Effect Class: 附加GE的Class
- Required Source Tags:需要Source的ASC含有的Tags
2. Period
Duration与Infinite设置了以后(Period != 0),每次触发相当于Instant,会修改BaseValue
- Execute Periodic Effect on Application: t=0的时候是否触发, 默认=true
- Periodic Inhibition Policy ----------> 与每次是否成功执行有关(
Ongoing Tag Requirements
)- Never Reset:周期的时间会继续,就好像抑制没有发生过一样。(依旧每次尝试执行)
- Reset Period:重置周期。下一次执行将在移除抑制后的一个完整周期内发生。(会重新
SetTimer
) - Execute and Reset Period: 立即执行并重置周期。(抑制接触后会立马调用一次,然后SetTimer。
SetTimerForNextTick->SetTimer
)
GE Period的执行是通过Timer来实现的,若Ongoing Tag Requirements
未满足GE会被标记为bIsInhibited = true
(这个变量在每次执行的时候会被拿来判断, 为false才能执行)
Periodic Inhibition Policy的作用,拿个例子来说一下。
GE1: Duration = 10s , Period = 1s. Modifiers: Health -= 10, Ongoing Tag Requirements:GE.Test
GE2: Duration = 2.2s, GrantedTags:GE.Test
初始时ASC没有Tag:GE.Test, 但Apply GE1,显然GE1不会起作用。若在2.5s Apply GE2,ASC会得到Tag:GE.Test,然后触发回调FActiveGameplayEffectsContainer::OnOwnerTagChange
, 随后标记GE1 bIsInhibited = false
。4.7s ASC失去Tag:GE.Test,标记GE1 bIsInhibited = true
此时情况如下所见:
- Never Reset:3.0s照常执行GE, 检测到
bIsInhibited = false
正常执行 Health -= 10; 4.0s类似; 5.0s执行失败- 执行时间: 3.0s 4.0s
- 效果Health -= 20
- Reset Period:2.5s 在标记
bIsInhibited = false
的同时, 会重新SetTimer
,因为Timer的覆盖性(同一个Handle,Timer重新Set以前的会失效),原来执行的Period会重新计算,所以下一次执行时间为3.5s; 4.5s执行第二次, 5.5s执行失败;- 执行时间:3.5s 4.5s
- 效果Health -= 20
- Execute and Reset Period: 与Reset Period相比, 在
SetTimer
之前会SetTimerForNextTick
。所以2.5s会多执行一次- 执行时间:2.5s 3.5s 4.5s
- 效果Health -= 30
3. Application
设置GE的应用概率和条件。
- Chance to Apply to Target:概率
- Application Requirement:GameplayEffectCustomApplicationRequirement类—>重载CanApplyGameplayEffect函数
4. Overflow
- Overflow Effects: Stakc溢出后, 可选择Apply的GE
- Deny Overflow Application: 溢出的GE不会影响Stack的刷新。比如Stack Limit Count=2,当第3个GE想要作用时,因为数量的限制不会叠加,但若Stack Duration Refresh Policy != NerverSet, 会刷新Duration, Period同理
- Clear Stack on Overflow: Stack溢出时, 是否会清空Stack。当Deny Overflow Application = true时才能勾选
5. Expiration
当Duration Policy不为Instant时, 才有此逻辑
- Premature Expiration Effect Classes: 打断时Apply的GE。
- Routine Expiration Effect Classes: 正常结束时Apply的GE
6. Display
- Require Modifier Success to Trigger Cues:当GE Modifiers或者Executions成功Apply时才能触发Cue
- Suppress Stacking Cues:多个GE存在Stack中时,是否只响应第一个GE
- 若勾选了,当多个GE存在于Stack时,只有第一个GE才能触发GC的
On Active
和While Active
事件
- 若勾选了,当多个GE存在于Stack时,只有第一个GE才能触发GC的
- Gameplay Cues:
- Magnitude Attribute: 选定一个Attribute获取它这次的修改值传递给GC,可通过GC Parameters的 Raw Magnitude 获得
- 比如说这次GE修改了Health,修改值为-10,则Raw Magnitude=-10。
- Min Level:
- 与Max Level配合使用,将GE Level标准化
- 计算规则:
(GE Level - Min Level) / (Max Level - Min Level)
Clamp 0.f-1.f - 可通过GC Parameters的 Normalized Magnitude 获得
- Max Level:
- Magnitude Attribute: 选定一个Attribute获取它这次的修改值传递给GC,可通过GC Parameters的 Raw Magnitude 获得
- UIData: GameplayEffectUIData类
GE的Duration Policy对GC触发事件类型的影响
- Instant: 立即触发
On Execute
事件 - Duration:
- Has Period: 最开始会触发
On Active
和While Active
事件,然后每次Period执行一次On Execute
事件。Duration结束会触发On Remove
事件。GE被Remove或抑制也会执行On Remove
事件 - No Period: 最开始会触发
On Active
和While Active
事件,Duration结束会触发On Remove
事件。GE被Remove或抑制也会执行On Remove
事件
- Has Period: 最开始会触发
- Infinite: 与Duration类似
注意事项:
- 关于
On Remove
事件的触发对于GC_Actor来说,只有勾选Auto Destroy on Remove
才能正确执行,不然只有GE第一次作用才能触发,后续不会再次触发 - 理论上GC类型的选择对于事件的触发无影响,但是
- GC_Static直接操作ClassDefaultObject(意味着没有实例),对于Instant效果(像击打伤害)是极好的.
- GC_Actor会在添加(Added)时生成一个新的实例, 因为其是实例化的, 所以可以随时间推移执行操作直到被移除(Removed). 这对循环的声音和粒子效果是很好的, 其会在持续(Duration)或无限(Infinite)GameplayEffect被移除或手动调用移除时移除. 其也自带选项来管理允许同时添加(Added)多少个(多个相同效果的应用默认只创建一个实例)
7. Tags
- GameplayEffectAssetTag: 标识GE的Tag
- Combined Tag为计算结果,不可编辑。 计算方式是
继承的Tag + Added - Removed
- Combined Tag为计算结果,不可编辑。 计算方式是
- GrantedTags: GE会赋予目标ASC的Tag,仅适用于Infinite和Has Duration的GE, GE失效后,Tag会从ASC上移除
- Combined Tag为计算结果,不可编辑。 计算方式是
继承的Tag + Added - Removed
- Instant不起作用
- Combined Tag为计算结果,不可编辑。 计算方式是
- GrantedBlockedAbilityTags: 当GE存在时,拥有这些Tag的GA不能执行。(与GA的Block Abilities with Tag作用一致)
- Combined Tag为计算结果,不可编辑。 计算方式是
继承的Tag + Added - Removed
- Instant不起作用
- Combined Tag为计算结果,不可编辑。 计算方式是
- Ongoing Tag Requirements: GE执行需要/不需要这些Tag, 这些标签会在 每次 执行时起作用。on/off,GE可以被Apply但off and do nothing
- Instant会起作用
- Application Tag Requirements: GE应用需要/不需要这些Tag, 这些标签只会在 第一次 应用Effect时才会被考虑, 而不是在每次周期执行时。pass/faild
- Instant会起作用
- Removal Tag Requirements: 当拥有/未拥有这些Tag,GE会被移除。GE持续时间内都有效
- Instant会起作用
- Remove Gameplay Effect Query: 更复杂的Remove GE的方法(笔者分析源码得出以下结论,但是实验的时候没有起作用,不能进行筛选 UE5.2.1)
- Custom Match Delegate BP: 一个Dynamic Unicast Delegate公开到蓝图中使用(但是我没发现怎么在蓝图使用), 返回bool
- Owning Tag Query:查询对应GE的
GameplayEffectAssetTag + GrantedTags + DynamicGrantedTags
- DynamicGrantedTags是GE Spec动态增加的GrantedTags---->
ASC->MakeOutgoingSpec->AddGrantedTags
- DynamicGrantedTags是GE Spec动态增加的GrantedTags---->
- Effect Tag Query:查询对应GE的
GameplayEffectAssetTag + DynamicAssetTags
- DynamicAssetTags是GE Spec动态增加的AssetTag---->ASC->MakeOutgoing Spec->AddAssetTags
- Source Tag Query:查询对应GE的Source Tags
- Modifying Attribute:查询对应GE修改的Attribute
- Effect Source:查询对应GE的Source Object
- Effect Definition:查询对应GE的Class
- Remove Gameplay Effects with Tags: 当GameplayEffect成功Apply后, 如果位于目标上的该GE在其Asset Tags或Granted Tags中有任意一个本标签的话, 其就会自目标上移除。
- Combined Tag为计算结果,不可编辑。 计算方式是
继承的Tag + Added - Removed
- 只在Apply时起作用, 若带有Tag的GE是在Apply之后添加的,是不能删除的
- Instant会起作用
- Combined Tag为计算结果,不可编辑。 计算方式是
8. Immunity
在GE持续时间内,赋予GE作用目标免疫其它GE能力(看其它文章说可以免疫GA,笔者未测试出这个效果)
- GrantedApplicationImmunityTags:
- Require Tags:其它GE有这些Tags(必须全部有)就会被免疫掉,可以免疫自己保证同一时间只有一个GE生效(Statck也不能生效)
- Ignore Tags:未测试出结果(按理说是GE没有这些Tags就会被免疫,但是不是的)
- Granted Application Immunity Query: 更复杂的GE判断,见 Tag-Remove Gameplay Effect Query解释(笔者同样没有实验成功这个功能)
使用该系统可以在GameplayEffect被免疫阻止时提供UAbilitySystemComponent::OnImmunityBlockGameplayEffectDelegate
委托(Delegate).
9. Stacking
当Duration Policy不为Instant时,才有Stack的概念
- Stacking Type: 叠加栈在目标身上or施法者身上
举个例子,假设层数为3,如果是by Target模式,那么3个敌人对我释放的Debuff只能叠三层。如果是by Source模式,那么3个敌人可以对我叠加9层Debuff。
每层Effect如果是Modifiers来计算,则为直接叠加的效果,比如用Modifiers来增加3攻击力,则第一层为增加3攻击力,则第二层为增加6攻击力,则第三层为增加9攻击力,而如果需要根据层数不同而改变增加的值,则需要使用Executions。 - Stack Limit Count: 层数
- Stack Duration Refresh Policy: Apply新GE时是否刷新Duration, 默认情况Overflow的GE会影响Stack刷新
- Stack Period Reset Policy: Apply新GE时是否刷新Period, 默认情况Overflow的GE会影响Stack刷新
- Stack Expiration Policy: 当一层GE的Duration到期后的处理方式
- Clear Entire Stack: 清空全部层数,如LOL征服者。
- Remove Single Stack and Refresh Duration:清空一层,如LOL致命节奏。
- Refresh Duration:不清空,相当于无限长的Duration,但可以通过调用
FActiveGameplayEffectsContainer::OnStackCountChange(FActiveGameplayEffect& ActiveEffect, int32 OldStackCount, int32 NewStackCount)
方法来自己处理细节,如一次掉两层。
使用细节:
- 开启Stack的方法为设置Stacking Type不为None
- 开启Stack后, Stack Limit Count层数为0代表可以无限叠加
- 不开启Stack, 多个GE同时起作用, 单独计算自己的Duration互不干扰
10. Granted Abilities
当Duration Policy不为Instant时,GE触发会赋予 Target GA。
InputID: 如果使用旧版输入,每一个操作映射都对应着一个枚举值,输入对应的枚举值就可以将这个新GA绑定到输入上。操作可参考Ability和绑定输入
Removal Policy:
- Cancel Ability Immediately: GE失效后,若Ability正在执行, 立即Cancel并Remove这个Ability
- Remove Ability on End: GE失效后,若Ability正在执行, 允许其执行完毕,并Remove这个Ability
- Do Nothing: GE失效后,不会Remove也不会Cancel,相当于永久拥有此Ability
Gameplay Cue
介绍GC_Actor部分参数
- Auto Destroy on Remove: 是否在On Remove事件后进行自动Destory Recycle(不是销毁Actor)
- 一般都是勾选上的,不然on Remove事件的触发会出现问题(见GE 6.Display)。
- On Remove事件不会销毁Acotr,只是进行了
SetActorHiddenInGame(true)
- Auto Destroy Delay: 勾选了Auto Destroy on Remove后,经过多少秒进行Destory
- Auto Attach to Owner: GC是否跟随Owner,若为true则会随着Owner移动。有性能损耗,需权衡
- Is Override: 这个GC是否会覆盖其它GC. 例如有两个GC, Tag分别为GC.One.Two与GC.One。若你通过GE调用GC.One.Two,若该值为false则会调用GC.One.Two与GC.One,若该值为true,则只会调用GC.One.Two
- Unique Instance Per Instigator: 这个GC是否为每个Instigator增加一个新的Instance? 例如,如果两个Instigator对同一个目标应用GC,我们是创建两个这样的GameplayCue Notify Actor还是一个?如果GC只是在目标上播放FX或声音,则不需要唯一Instance。如果此Notify将一个光束从Instigator附加到目标,则每个Instigator确实需要一个唯一的Instance。
- Unique Instance Per Source Object: 与Unique Instance Per Instigator类似,只不过判断目标是Source Object。
- Source Object与Instigator对应着Parameters上的
- 默认情况对于同一个目标,GC只会产生一个Instance
- Allow Multiple on Active Events: 当GC正在执行时,来一个请求再次触发GC,是否会再次触发
On Active
事件 - Allow Multiple While Active Events: 当GC正在执行时,来一个请求再次触发GC,是否会再次触发
While Active
事件 - Num Preallocated Instances: 为GC Instance预先分配内存空间