UE5-GAS插件UE5.3改动

Unreal在前段时间发布5.3版本后的某天,我将自己写着玩的游戏切到了新版本,如往常一样打开了我的项目,创建了一个GE后惊呆了,好家伙,你是谁?你还是我认识的GE嘛?你变了!于是我想这写一篇文章大致过一遍GAS插件5.3的改动,其它部分变化不大,主要是GE进行了大改。

Gameplay Effect

是的,你没有看错,新的GE就长这样,从原来密密麻麻的一排配置项,变成了现在只有这么一丢丢了,老的代码自动转成了新的配置实现,GE原来功能变成了可配置的component。GE现在的功能变成了通过配置组件去实现。

看到这个新布局,我第一时间想到的就是Lyra项目中的物品系统,每一个item的属性和功能是通过Fragment组件来决定的。

如下图,Lyra一个手枪的物品的属性是由五个fragment决定的,Equippable Item决定了手枪作为装备的功能,Quick Bar Icon和Pickup Icon决定了手枪的UI表现,Set Stats为手枪的tag信息,Reticle Config应该决定了准心的表现。物品的类型和功能不再像一般的做法通过类的继承和派生实现,装备,消耗品等功能都可以通过一个个Fragment去实现和配置。

5.3中Gameplay Effect的思路也和物品类似,通过组件来决定GE的属性和功能。话不多说,打开源码,看看GE是如何实现的。在GameplayEffect中对应的属性为GEComponents数组.

GE功能组件类名为GameplayEffectComponent,继承于Object。首先看一看注释:

这是5.3推出的新功能,GEComponent在理解GE流程和小心维护回调基础上,避免了通过一大堆的接口去实现期望的功能,可以极大的减少代码时间。

GEComponent依赖于GE,和GE一样,对于多个释放的GE,都具有相同的GEComponent(关系应该类似于GameplayEffect和ActiveGameplayEffect的关系,GE本身是不会实例化的,激活的GE只是存了GE的CDO引用)因此,GEComponent不应该也不能存储数据,当前版本实现数据获取是通过delegate带来数据回调。因此当前仍然有一些数据需要存储在GE(应该是Active GE结构体)中,未来会在GE Spec中存储额外的数据以实现功能的扩展。

以前配置在GE中的功能,比如AssetTags,GrantTags,Conditional Effect等,现在被划分到了一个个GEComponent当中,通过配置的方式去添加

下图就是5.3官方提供的GE Component,基本上就是之前GE已有的功能,比如Asset Tags现在变成了Asset Tags Component。通过这种方式,让我们扩张GE的属性和功能变得比以前方便太多,只需要派生一个自己的GE Component即可。

接下来开始看GEComponent中的函数,GEComponent的功能实现都是通过在子类中,按照需求重写对应的函数,在对应的时机触发需要的逻辑。

函数名触发条件和作用网络同步
CanGameplayEffectApply用于判断GE是否可以成功被Apply,如果返回false,则GE会添加失败Server, Predict Client
OnActiveGameplayEffectAdded对于持续性的GE生效,当GE被添加至角色身上时生效,如果GE设置了堆叠Stack,则只会在Stack为空的时候才会生效Server, Owning Client
OnGameplayEffectExecuted对于InstantGE生效(Period GE可以被视为周期性的触发Instant GE),当GE Execute时触发Server
OnGameplayEffectApplied对所有的GE都会生效,周期性GE只会在添加时触发一次All

在继续讨论这四个函数具体功能的时候,先解释一下ActiveGameplayEffect,该结构体可以被理解为实例化的GE,也就是实际挂在角色身上的GE数据。我们可以知道GE本身是没有实例化的,所以诸如 暂停/激活,持续时间改变,被移除等等事件,是没有办法直接从GE上回调的,他们实际上发生在ActiveGameplayEffect,由此触发

ActiveGameplayEffect其中一个属性EventSet提供了激活的GE上可绑定的回调事件,GEComponent上使用的也是这里的事件,比如GE Component会在持续时间内给予目标技能组,我们可以在OnActiveGameplayEffectAdded时调用Grant Ability,那么如何知道GE结束了呢,这个时候就需要绑定EventSet中的OnEffectRemoved,这也是官方代码中AbilitiesGameplayEffectComponent的做法

其中包含了四个Delegate,分别代表了Active GE被移除,Stack Active GE的堆栈发生变化,Active GE的持续事件发生变化,Active GE的激活状态发生改变。

在GE Component中监听GE Remove的方法示例

CanGameplayEffectApply

CanGameplayEffectApply,用于决定GE是否能成功被Apply,一个GE身上的所有components必须都返回true,才能被成功的apply。默认返回true

代码的执行顺序为,ASC调用函数ApplyGameplayEffectSpecToSelf(所有Apply Effect的函数最终都会调用此函数起实际作用),函数中会调用Gameplay Effect的CanApply函数,如果返回false,则GE会添加失败,返回一个空的ActiveGEHandle

GE中的CanApply函数会遍历GE的GEComponents,调用CanGameplayEffectApply函数,只要有一个返回false,则GE无法被成功Apply

OnActiveGameplayEffectAdded

当GE被添加到ActiveGameplayEffectsContainer中时调用,当GE有持续时间时才会被添加到container中,意味着这个函数只对duration和infinite的GE生效。返回true则意味着GE需要保持激活,如果返回false则会被暂停,暂停并不意味着被移除,它仍然会等待这被激活。这个函数是会被replicate的,意味着GE目标的主控端也会调用此函数。

如果函数返回false,则GE会被停止,停止并不意味着被移除,如果条件变为true了,GE会再次生效

执行顺序如下

首先还是ASC的ApplyGameplayEffectSpecToSelf,如果GE有持续时间,或者因为预测需要将instant GE视为一个Infnite GE,会调用ASC的GE存储容器的函数ApplyGameplayEffectSpec

ApplyGameplayEffectSpec最终会生成一个结构体ActiveGameplayEffect并添加并储存起来,GE的效果也都是在这里起效的。

在函数的最后,调用InternalOnActiveGameplayEffectAdded表明GE已经被成功的添加至Active Effect Container,似乎如果GE设置为堆叠,Add就不会起效了。

InternalOnActiveGameplayEffectAdded将会调用GE的OnAddedToActiveContainer

终于,OnAddedToActiveContainer函数中会遍历GE的GEComponents,调用OnActiveGameplayEffectAdded

OnGameplayEffectExecuted

当GE被执行时调用,GE的执行只会在Role_Authority下的Instant GE才会被执行,对于有period的GE来说,它的每一次执行都可以被视为周期性的执行instant GE。

GE的执行是如何触发的呢?首先对于instant GE来说,GE并不会生成Active GE添加到容器中,因此在ASC里会调用ExecuteGameplayEffect函数让GE效果生效。对于周期性的GE来说,由于它具有持续时间,会被添加到Active GE容器中,周期性的调用Container中的函数InternalExecutePeriodicGameplayEffect,然后调用ExecuteGameplayEffect让GE效果生效,和instant GE的流程一致。

FActiveGameplayEffectsContainer::ExecuteActiveEffectsFrom->GE::OnExecuted

GE::OnExecuted -> GEComponent::OnGameplayEffectExecuted

OnGameplayEffectApplied

当GE被释放或者堆叠时调用,duration和instant GE都会触发Apply,对于周期性的GE,该函数不会多次触发,只会在刚生效时触发一次。和Execute和Add不同,Apply函数是会网络同步的!EPIC也更推荐在此函数中实现自己的功能

OnGameplayEffectApplied的调用顺序还是从ASC的ApplyGameplayEffectSpecToSelf开始,调用GE函数OnApplied,在OnApplied中遍历GEComponent调用OnGameplayEffectApplied

GEComponent类及其功能

这里介绍一下当前插件中已经实现的GE Component,基本上都是原有的GE功能,并进行了一定程度的更改和扩展。以前想要扩展GE的功能会比较麻烦,但是现在扩展变得十分简单了,读者如果想要实现一些自己特定的GE功能,可以从找一个类似机制的GE Component参考

AbilitiesGameplayEffectComponent

老版本的GrantAbility,作用是在GE生效期间给予角色技能

实现方法为重写OnActiveGameplayEffectAdded函数,监听ActiveGE的移除和暂停状态,中止状态为false为GE激活,此时调用GrantAbilities,而当GE被暂停或移除时,则调用RemoveAbilities

AdditionalEffectsGameplayEffectComponent

作用是GE生效时可以触发额外的GE,分别有四个配置项,分别代表不同条件下触发的GE。

  • OnApplicationGameplayEffects:GE Apply时触发的额外GE
  • OnCompleteAlways:GE结束时触发的额外GE,无论是何种条件导致的
  • OnCompleteNormal:GE因为持续时间结束,正常结束时触发的额外GE
  • OnCompletePrematurely:GE因为意外情况被移除时,触发的额外GE

这里会再提一下该GE是如何通过ActiveGameplayEffect中的Delegate触发额外GE的。

对于OnCompleteAlways GEs来说,也就是GE结束时触发的额外GE。在函数OnActiveGameplayEffectAdded中监听了此Active GE被Remove的委托

触发的函数OnActiveGameplayEffectRemoved,则会遍历OnCompleteAlways ,然后Apply

AssetTagsGameplayEffectComponent

替代原有的GE中的配置项Asset Tags

BlockAbilityTagsGameplayEffectComponent

替代原有的Block Ability Tags,可以阻止特定tag的技能激活

生效的机制为配置tag后,会对GE的CachedBlockedAbilityTags进行修改

当GE激活时,会将BlcokTags注册进ASC中

ChanceToApplyGameplayEffectComponent

用于设置GE成功Apply的概率

CustomCanApplyGameplayEffectComponent

这里配置自己实现的GE Apply条件,来决定GE释放是否可以成功

GameplayEffectUIData_TextOnly

用于配置GE的UI信息,这里只有一个简单的TEXT,有需要的可以派生UGameplayEffectUIData类去添加自己需要的数据信息

ImmunityGameplayEffectComponent

配置角色免疫其它GE的条件

RemoveOtherGameplayEffectComponent

配置移除其它GE

TargetTagRequirementsGameplayEffectComponent

配置Tag条件,满足特定的条件GE就能执行对应的阶段。Application决定的是GE能否成功的释放到角色身上,OnGoing决定的是GE是否处于激活状态,即使没有激活,GE仍然是在角色身上的,Remove决定了GE移除的条件,当条件满足时,GE会被移除。

TargetTagsGameplayEffectComponent

替代原有的Grant Tags功能,实现方法和BlockAbilityTagsGameplayEffectComponent类似

尝试实现Custom Effect Component

这个部分尝试实现一个自定义功能的Effect Component,功能类似于AdditionalEffectsGameplayEffectComponent,在GE生效后会再Apply一些额外的GE效果,区别在于,额外释放的GE持续时间依赖于源GE,如果GE失效,则它释放的额外GE也会失效。我知道这个功能通过现有的配置完全可以实现,但是策划会觉得太难太复杂,有时候就是需要额外的再写功能。这里我写的很简单,只是为了做一个示范尝试。

首先创建在C++中创建UGameplayEffectComponent的子类,重写OnActiveGameplayEffectAdded和OnGameplayEffectApplied两个函数

OnActiveGameplayEffectAdded中绑定一个委托,调用自己实现的函数OnActiveGameplayEffectRemoved,将添加的GE进行移除

OnGameplayEffectApplied中遍历OnGrantEffects,然后ApplyEffect

OnActiveGameplayEffectRemoved的实现也很简单,遍历OnGrantEffects然后移除GE

测试一下,创建一个测试GE,添加刚才实现的Component

可以看到GE_Test生效期间成功释放了一个额外的GE_Test_Grant,15s后持续时间结束,两个GE都被成功的移除。

其它改动

GameplayModMagnitudeCalculation

Bug修复

这个类时用于GE中自定义Modifier中修改某种属性的数值,在5.3中给K2_GetCapturedAttributeMagnitude等功能函数加上了const修饰符,这个bug也是挺搞笑的,在5.0-5.2这个类用于获取属性,Tag的函数全都因为没有const修饰符是无法调用的,现在使用不需要修改源代码或者自己加函数了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值