GameplayAbility
Gameplay abilities是GAS中关于技能的抽象,可以非常傻瓜地实现法术,技能等等。除了可以实现冷却时间,技能消耗等其他RPG游戏中常见的施法机制外,还能自定义Ability Task来定制gameplay ability。这些tasks是在技能激活期间异步进行的,tasks中可以控制角色动画,粒子、声音效果等等,一旦任务完成或是接受到特定事件后,通过callback返回。Gameplay Ability支持replication。
举几个Abilities例子:
- 等待一个动画播放完毕后释放火球魔法。
- 按住按键吟唱火球魔法术,松开按键后发射火球。
- 你甚至可以在释放火球前,让玩家玩DDR(跳舞机),根据玩家的手指舞蹈技术来决定火球魔法的强度。
Granting and Revoking Abilities(赋予和收回能力) [ Only on Server !!!]
赋予能力
在Actor可以使用Ability之前,Actor的Ability System Component需要被赋予能力。实现的方法为:
- GiveAbilityAndActivateOnce: 赋予能力并尝试执行一次,在执行完成后,能力被收回(用得不多)
-
GiveAbility: 通过传入FGameplayAbilitySpec结构体,赋予能力,返回FGameplayAbilitySpecHandle(对于Ability的唯一标识)。Ability必须被实例化,并能在服务器上运行。在服务器上尝试运行Ability后,会返回FGameplayAbilitySpecHandle。如果Ability不满足标准,或者不能执行,则返回无效值。Ability System Component无法被赋予能力。
赋予能力时,其实传入的参数中有InputID,这涉及到Ability的输入绑定。你的能力总是要绑定到一个用户输入上吧,这样玩家才能施放能力。绑定的方式在后面在介绍Gameplay Ability Component的文中叙述。
赋予能力后需要调用InitAbilityActorInfo来配置Owner Actor和Avatar Actor,通常在PossessedBy函数中调用,应为更换Controller时,注册的信息(ActorInfo)会过时。
收回能力
使用之前的FGameplayAbilitySpecHandle(对于Ability的唯一标识)作为输入,可以移除指定Ability。
- ClearAbility: 移除指定能力
- SetRemoveAbilityOnEnd: 当能力执行完毕后,移除指定能力。如果能力不在执行中,则直接移除;若在执行中,则该能力的输入会被清空,玩家无法再激活或是和该能力交互。
-
ClearAllAbilities: 移除所有能力,不需要FGameplayAbilitySpecHandle。
Basic Usage(基本用法)
获得能力后,使用Ability的基本执行周期为:
1、 CanActivateAbility 让玩家在尝试使用能力之前知道是否可以激活该能力。比如,当能力不能激活是,UI图标变灰。
2、 CallActivateAbility 不检查能力是否可激活,直接调用能力。这个函数通常在CanActivateAbility和执行能力之间调用。
- 玩家为实现自定义的Ability功能,主要的方式就是重写ActivateAbility方法,或是在蓝图中实现Activate Ability事件。
- Gameplay Ability没有“tick”函数,而是通过Ability task异步执行。
- Commit Ability函数在Activate Ability中调用,在这里应用执行能力的代价计算(如,蓝量,体力等资源的消耗,即Gameplay Attribute的减法,还有应用技能冷却等等)。
- CancelAbility 提供机制以取消技能,CanBeCanceled可以拒绝这个函数执行。函数会调用OnGameplayAbilityCancelled,可以在此处做相关的清理。
3、TryActivateAbility 典型执行Ability的方法。会先调用CanActivateAbility进行检测,通过后调用CallActivateAbility。
4、 EndAbility 结束Ability的执行。除了CancelAbility会自动调用该函数,其他情况下都要手动调用该函数或是在蓝图中添加End Ability节点来结束Ability的执行,否则会产生各种bug。
Tags
Gameplay Tags用于Gameplay Abilties之间的相互交互。
除了Tags变量,还有其他由引擎提供的变量供配置,如:Costs,Cooldowns,Ability Trigger等等。
Advanced(高级)
https://docs.unrealengine.com/en-us/Gameplay/GameplayAbilitySystem/GameplayAbility
Replication
Gameplay Abilities支持内部状态的replication和Gameplay Event,也可以关闭replication节省资源。Gameplay Ability Replication Policy可以被设置为“Yes”或“No”来打开或关闭replication。还可以设置Gameplay Net Execution Policy控制Ability如何replicate。共有四种方式:
- Local Predicted: 启用客户端预测,服务端可以回滚,可以减小延迟感。
- Local Only: Ability只会在客户端运行,但改变的数值仍会replicate到服务端,也可以接受服务端的校正。
- Server Initiated: Abilities由服务端初始化,然后通过网络传输到客户端,可以保证精确,但是可能会出现延迟感。
- Server Only: Abilities只在服务端运行,数值会通过网络同步给客户端,客户端也仍能观察到能力视觉效果。
还未试验过,大家可以尝试看看不同方式的效果。
Instancing Policy(实例化策略)
每当Ability执行时,系统会生成一个新的该Ability类实例用以跟踪当前Ability的进展。但如果Ability使用频繁,或者存在大量的单位,则类的大量实例化会导致性能问题。引擎提供了三种策略来平衡性能问题。
- Instanced per Execution: 每次执行Ability都会生成一个新的Ability对象。这种方法无疑是开销最大的。它的优势是你可以随意的使用蓝图和成员变量,所有的对象都会在执行能力前被初始化。这是最容易实现的实例化策略,适用于不频繁使用的Ability,比如具有长CD的技能。
- Instance per Actor: 每个Actor在第一次执行Ability时,会生成该Ability的实例,之后重用这个对象。这就需要我们清理成员变量,并能保存每次执行的信息。这种方法是开销较小,在大规模的情况下也有不错的表现。
- Non-Instanced: 最高效的策略。执行时不会生成任何实例,而是使用该类的Class Default Object。但这种方法存在一些限制。首先,无法使用蓝图Graph(需要Object Instance),只能使用C++。可以构建蓝图类,但是只能改变暴露的变量值。Ability执行中不能改变成员变量值,不能绑定delegate。不能replicate变量和处理RPCs。这种策略使用于不改变内部变量(可以修改Attributes),不需要replicate任何数据的Ability。特别适用于频繁被大量Actor使用的技能,如RTS或MOBA中的基本攻击。
Triggering with Gameplay Events
Gameplay Events是一个数据结构,可以直接触发Gameplay Abilities,与上文描述的使用ability方式不同,是另一条执行ability的方式。 通常使用Gameplay events的方法是调用Send Gameplay Event To Actor并提供实现了IAbilitySystemInterface的Actor,和所需要的上下文信息。也可以直接在Ability System Componet上处理Gameplay Event。
注意!
当Gameplay Ability由Gameplay Event触发时,Ability不会走Activate Ability这条路,而是使用Activate Ability From Event 并提供更多的上下文信息。如果在蓝图Graph中实现了Activate Ability From Event,则Activate Ability就不会再被执行了。