(翻译 ue gas) Gameplay Ability

https://dev.epicgames.com/documentation/en-us/unreal-engine/using-gameplay-abilities-in-unreal-engine

Gameplay Ability

Overview of the Gameplay Ability class.

A Gameplay Ability, derived from the UGameplayAbility class, defines what an in-game ability does, what (if anything) it costs to use, when or under what conditions it can be used, and so on. Because Gameplay Abilities are capable of existing as instanced objects running asynchronously, you can run specialized, multi-stage tasks involving character animation, particle and sound effects, and even branching based on player input or character interactions that occur during execution. Gameplay Abilities can replicate themselves across the network, run on client or server machines (including client-side prediction support), and even sync variables and make Remote Procedure Calls (RPCs). Gameplay Abilities also provide flexibility in terms of how the Engine implements them during a game session, such as extensible functionality to implement cooldown and usage costs, player input, animation with Anim Montages, and reacting to the Ability itself being granted to an Actor.

Gameplay Ability 是从 UGameplayAbility 类派生出来的,它定义了一个游戏中技能的功能,包括其作用、是否有使用代价、何时或在什么条件下可以使用等内容。

由于 Gameplay Abilities 能够作为异步运行的实例对象存在,因此你可以运行一些特殊的、多阶段的任务,这些任务可以涉及角色动画、粒子和音效,甚至可以根据执行过程中玩家的输入或角色交互来进行分支。

Gameplay Abilities 可以在网络中实现自我复制,可以在客户端或服务器上运行(包括客户端预测的支持),并且可以同步变量和进行远程过程调用(RPC)。

Gameplay Abilities 还在游戏过程中提供了灵活的实现方式,比如可扩展的功能,用于实现冷却时间和使用代价、玩家输入、使用动画蒙太奇(Anim Montages),以及响应技能被赋予给某个 Actor 的事件等。

 

Granting and Revoking Abilities

Before an Actor can use an Ability, its Ability System Component must be granted that Ability. The following Ability System Component functions can grant access to an Ability:

  • GiveAbility: Specifies the Ability to add with an FGameplayAbilitySpec, and returns an FGameplayAbilitySpecHandle. Only the server can give or revoke Abilities.

  • GiveAbilityAndActivateOnce: Specifies the Ability to add with an FGameplayAbilitySpec, and returns an FGameplayAbilitySpecHandle. Because only the server can give Abilties, the Ability must be instanced and able to run on the server. After attempting to run the Ability, a FGameplayAbilitySpecHandle will be returned. If the Ability did not meet the required criteria, or if it could not execute, the return value will be invalid and the Ability System Component will not be granted the Ability.

Similar to giving abilities, only the server can remove abilities. The following functions can revoke access to an Ability from an Ability System Component, using the FGameplayAbilitySpecHandle that was returned when the Ability was granted:

  • ClearAbility: Removes the specified Ability from the Ability System Component.

  • SetRemoveAbilityOnEnd: Removes the specified Ability from the Ability System Component when that ability is finished executing. If the Ability is not executing, it will be removed immediately. If the Ability is executing, its input will be cleared immediately so that the player cannot reactivate or interact with it any further.

  • ClearAllAbilities: Removes all Abilities from the Ability System Component. This function is the only one that does not require an FGameplayAbilitySpecHandle.

授予与移除技能(Granting and Revoking Abilities)

在一个 Actor 能够使用某个技能之前,Ability System Component 必须被授予该技能。以下的 Ability System Component 函数可以用来授予技能:

  • GiveAbility:使用一个 FGameplayAbilitySpec 指定要添加的技能,并返回一个 FGameplayAbilitySpecHandle。只有服务器可以授予或移除技能。

  • GiveAbilityAndActivateOnce:使用一个 FGameplayAbilitySpec 指定要添加的技能,并返回一个 FGameplayAbilitySpecHandle。由于只有服务器可以授予技能,该技能必须是实例化的并能够在服务器上运行。在尝试运行该技能后,会返回一个 FGameplayAbilitySpecHandle。如果该技能不符合要求,或者无法执行,返回值将无效,并且 Ability System Component 不会被授予该技能。

与授予技能类似,只有服务器可以移除技能。以下函数可以使用在授予技能时返回的 FGameplayAbilitySpecHandle 来撤销 Ability System Component 对技能的访问权限:

  • ClearAbility:从 Ability System Component 中移除指定的技能。

  • SetRemoveAbilityOnEnd:在指定的技能执行完成后,从 Ability System Component 中移除该技能。如果该技能当前未在执行,则会立即被移除;如果正在执行,其输入会立即被清除,以防玩家再次激活或与之交互。

  • ClearAllAbilities:从 Ability System Component 中移除所有技能。这个函数是唯一一个不需要 FGameplayAbilitySpecHandle 的函数。

 

Basic Usage

A Gameplay Ability's basic execution lifecycle, after being granted to an Actor's Ability System Component, looks like this:

  1. CanActivateAbility lets the caller know whether or not an Ability is available for execution without attempting to execute it. For example, your user interface may need to gray out and deactivate icons that the player can't use, or play a sound or particle effect on the character to show that a certain Ability is available.

  2. CallActivateAbility executes the game code associated with the Ability, but does not check to see if the Ability should be available. This function is usually called in cases where some logic is needed between the CanActivateAbility check and the execution of the Ability.
    • The main code that users need to override with their Ability's custom functionality is either the C++ function called ActivateAbility, or the Blueprint Event called Activate Ability.

    • Gameplay Abilities do not carry out their primary work in a "tick" function like Actors and Components do. Instead, they launch Ability Tasks during activation which do most of the work asynchronously, and then handle the output of those Tasks by hooking into Delegates (in C++) or connecting nodes to output execution pins (in Blueprints).

    • The CommitAbility function, if called from within Activate, will apply the cost of executing the Ability, such as by subtracting resources from Gameplay Attributes (such as "magic points", "stamina", or whatever fits your game's systems) and applying cooldowns.

    • CancelAbility provides a mechanism to cancel the Ability, although the Ability's CanBeCanceled function can reject the request. Unlike CommitAbility, this function is available for callers outside of the Ability itself. A successful cancelation will broadcast to On Gameplay Ability Cancelled before going through the standard code path for ending the Ability, giving the Ability a chance to run special cleanup code or otherwise behave differently when canceled than it would if it had ended on its own terms.

  3. TryActivateAbility is the typical way to execute Abilities. This function calls CanActivateAbility to determine whether or not the Ability can run immediately, followed by CallActivateAbility if it can.

  4. EndAbility (in C++) or the End Ability node (in Blueprints) shuts the Ability down when it is finished executing. If the Ability was canceled, the UGameplayAbility class will handle this automatically as part of the cancelation process, but in all other cases, the developer must call the C++ function or add the node into the Ability's Blueprint graph. Failing to end the ability properly will result in the Gameplay Ability System believing that the Ability is still running, and can have effects such as preventing future use of the Ability or any Ability that it blocks. For example, if your game has a "Drink Health Potion" Gameplay Ability that doesn't end properly, the character using that Ability will be unable to take any action that drinking a health potion would prevent, such as drinking another potion, sprinting, climbing ladders, and so on. This Ability blockage will continue indefinitely, since the Gameplay Ability System will think that the character is stil busy drinking the potion.

基本用法(Basic Usage)

一个 Gameplay Ability 被授予给 ActorAbility System Component 后,其基本的执行生命周期如下:

  • CanActivateAbility 让调用者知道该技能当前是否可以执行,但不会尝试实际执行它。例如,你的用户界面可能需要将玩家当前不能使用的技能图标变灰并禁用,或者在角色身上播放音效或粒子效果来表示某个技能已可用。

  • CallActivateAbility 执行与该技能关联的游戏代码,但不会检查该技能是否应该可以使用。这个函数通常用于在 CanActivateAbility 检查与实际执行之间需要额外逻辑处理的情况。

  • 用户需要重写的主要代码是:C++ 中的 ActivateAbility 函数,或者蓝图中的 Activate Ability 事件。

Gameplay Abilities 并不像 ActorComponent 那样通过 “tick” 函数来执行其主要工作。它们在激活时会启动 Ability Tasks 来执行大部分异步工作,并通过 C++ 中的 Delegates 或蓝图中的输出执行引脚来处理这些任务的输出。

  • CommitAbility 函数,如果在 Activate 函数中调用,将会应用技能的使用代价,例如从 Gameplay Attributes(如“魔法值”、“体力”等)中扣除资源并触发冷却时间。

  • CancelAbility 提供了一种机制来取消技能的执行,尽管技能的 CanBeCanceled 函数可以拒绝取消请求。与 CommitAbility 不同,这个函数可以被技能外部的调用者使用。成功取消技能后,会广播 On Gameplay Ability Cancelled,然后进入技能结束的标准流程,允许技能在取消时运行特殊的清理代码,或在被取消的情况下以不同于正常结束的方式表现。

  • TryActivateAbility 是执行技能的典型方式。这个函数先调用 CanActivateAbility 检查技能是否可以立即执行,如果可以,则继续调用 CallActivateAbility

  • EndAbility(在 C++ 中) 或蓝图中的 End Ability 节点用于在技能执行完毕后关闭该技能。如果技能是被取消的,UGameplayAbility 类会在取消流程中自动处理,但在其他情况下,开发者必须手动调用 C++ 函数或在蓝图图表中添加节点来结束技能。如果未正确结束技能,Gameplay Ability System 会认为该技能仍在运行,这可能导致无法再次使用该技能,或无法使用被其阻止的其他技能。

例如,如果你的游戏中有一个“喝治疗药水”的技能,但它没有正确结束,那么角色将无法进行任何该技能会阻止的动作,例如再喝一瓶药水、冲刺或爬梯子等。这种技能阻塞会无限持续,因为 Gameplay Ability System 会认为角色仍在喝药水。

 

Tags

Gameplay Tags can help to determine how Gameplay Abilities interact with each other. Each Ability possesses a set of Tags that identify and categorize it in ways that can affect its behavior, as well as Gameplay Tag Containers and Gameplay Tag Queries to support these interactions with other Abilities.

Gameplay Tags 可以帮助判断 Gameplay Abilities 之间如何相互作用。每个技能拥有一组标签,这些标签用于识别和分类该技能,并可能影响其行为。此外,还可以使用 Gameplay Tag ContainersGameplay Tag Queries 来支持与其他技能之间的交互。

Gameplay Tag Variable(s)Purpose
Cancel Abilities With Tag Cancels any already-executing Ability with Tags matching the list provided while this Ability is executing.
Block Abilities With Tag Prevents execution of any other Ability with a matching Tag while this Ability is executing.
Activation Owned Tags While this Ability is executing, the owner of the Ability will be granted this set of Tags.
Activation Required Tags The Ability can only be activated if the activating Actor or Component has all of these Tags.
Activation Blocked Tags The Ability can only be activated if the activating Actor or Component does not have any of these Tags.
Target Required Tags The Ability can only be activated if the targeted Actor or Component has all of these Tags.
Target Blocked Tags The Ability can only be activated if the targeted Actor or Component does not have any of these Tags.

 

Gameplay Tag 变量用途
Cancel Abilities With Tag 在该技能执行期间,取消所有已在执行且标签与提供的列表匹配的技能。
Block Abilities With Tag 在该技能执行期间,阻止任何具有匹配标签的其他技能被执行。
Activation Owned Tags 当该技能执行时,技能的拥有者会被赋予这一组标签。
Activation Required Tags 只有在激活的 Actor 或 Component 拥有所有这些标签时,该技能才能被激活。
Activation Blocked Tags 只有在激活的 Actor 或 Component 不包含任何这些标签时,该技能才能被激活。
Target Required Tags 只有在目标 Actor 或 Component 拥有所有这些标签时,该技能才能被激活。
Target Blocked Tags 只有在目标 Actor 或 Component 不包含任何这些标签时,该技能才能被激活。

 

Replication

Gameplay Abilities support replication of internal state and Gameplay Events, or to turn replication off and save network bandwidth and CPU cycles. The Ability's Gameplay Ability Replication Policy can be set to "Yes" or "No", and this will control whether the Ability replicates instances of itself, makes state updates, or sends Gameplay Events across the network. This is not the same as replicating the activation or ending of the ability, which can occur regardless of that setting.

For multiplayer games with Abilities that do replicate, there are a few options for how replication is handled, known as the Gameplay Net Execution Policy:

  1. Local Predicted: This option provides a good balance of responsiveness and accuracy. The Ability will run on the local client immediately upon the client issuing the command, but the server will have the final word, and can override the client in terms of what the Ability's actual impact was. The client is effectively asking permission from the server to execute the Ability, but also proceeding locally as if the server is expected to agree with the client's view of the outcome. Because the client is locally predicting the behavior of the Ability, it will feel perfectly smooth and lag-free as long as the server does not contradict the client's prediction.

  2. Local Only: The client simply runs the Ability locally. There is no replication to the server, although the Ability will run on the server if the client using it is the host (playing on the physical server machine), or if this is a single-player game. This does not apply to dedicated-server games, as there is never a client playing on the server machine. Anything the client affects with this Ability will still follow normal replication protocol, including potentially receiving corrections from the server.

  3. Server Initiated: Abilities that initiate on the server will propagate to clients. These are often more accurate, from the client's perspective, to what is actually happening on the server, but the client using the Ability will observe a delay due to the lack of local prediction. While this delay should be very short, some types of Abilities, especially rapidly-performed actions in pressured situations, will not feel as smooth as they would in Local Predicted mode.

  4. Server Only: "Server Only" Abilities will run on the server, and will not replicate to clients. Any data outside of the Gameplay Ability will replicate as normal. In this way, the Ability can still have effects that clients observe, even though the Ability itself will only run on the server.

Replication
Gameplay Abilities 支持其内部状态和 Gameplay Events 的 Replication,也可以关闭 Replication,以节省网络带宽和 CPU 资源。Ability 的 Gameplay Ability Replication Policy 可设为 “Yes” 或 “No”,用来控制该 Ability 是否会复制其实例、更新状态,或在网络中发送 Gameplay Events。这个设置与 Ability 的激活或结束是否被复制无关——这些行为无论设置如何都可能发生。

对于在多人游戏中需要进行 Replication 的 Ability,有几种 Replication 策略,称为 Gameplay Net Execution Policy

本地预测(Local Predicted)
这种方式在响应速度与准确性之间提供良好的平衡。客户端在发出指令后会立刻在本地执行 Ability,但最终的判定权在服务器,服务器可以对客户端所认为的执行结果进行覆盖。客户端等于是在向服务器请求许可的同时,预设服务器会同意,从而继续本地执行。由于客户端进行了本地预测,只要服务器的反馈与其一致,使用体验将非常顺畅且无感延迟。

仅本地(Local Only)
客户端仅在本地运行 Ability,不会将其 Replicate 到服务器。不过如果客户端是主机(在服务器机器上运行)或是在单人模式中,则 Ability 同样会在服务器上运行。在专用服务器(Dedicated Server)环境下,此方式不适用,因为不会有客户端直接运行在服务器上。Ability 所产生的影响依然遵循正常的 Replication 流程,包括可能会从服务器收到的状态修正。

服务器发起(Server Initiated)
Ability 由服务器发起,并同步到客户端。从客户端角度来看,这种方式能够更准确地反映服务器的实际状态。但由于缺少本地预测,客户端在观察到 Ability 效果前会有一定延迟。虽然这个延迟通常较短,但对于需要快速操作的能力,尤其在高压场景中,体验上会比 Local Predicted 稍显卡顿。

仅服务器(Server Only)
这类 Ability 只在服务器上运行,不会 Replicate 到客户端。不过 Ability 之外的相关数据仍然会正常 Replicate。因此,尽管 Ability 本体仅在服务器上执行,它产生的效果客户端仍然可以观察到。

 

Instancing Policy

When a Gameplay Ability executes, a new Object (of the Ability's type) will usually spawn to track the Ability in progress. Since Abilities can execute very frequently in some cases, such as battles between a hundred or more players and AI characters in Battle Royale, MOBA, MMO, or RTS games, there may be cases where rapid creation of Ability Objects can negatively impact performance. To address this, Abilities have a choice of three different instantiantion policies, offering tradeoffs between efficiency and functionality. The three supported instancing types supported are:

  • Instanced per Execution: A copy of the Ability's Object will spawn each time the Ability runs. The advantage to this is that you can use Blueprint graphs and member variables freely, and everything will be initialized to default values at the beginning of the execution. While this is the simplest instancing policy to implement, it is ideal for Abilities that run infrequently due to the larger overhead involved. For example, an "Ultimate" in a MOBA would be a reasonable use case, as there tends to be a long cooldown (usually 60-90 seconds) between executions, and there are only a few characters (usually about ten) who can use these Abilities at all. A basic attack Ability used by the computer-controlled "minions" would be a poor candidate, as there may be hundreds of them at a time, and each can issue basic attacks fairly frequently, causing rapid creation (and possibly replication) of new Objects.

  • Instanced per Actor: Each Actor will spawn one instance of this Ability when the Ability is first executed, and future executions will reuse it. This creates the requirement to clean up member variables between executions of the Ability, but also makes it possible to save information across multiple executions. Per-Actor is ideal for replication, as the Ability has a replicated Object that can handle variable changes and RPCs, but does not waste network bandwidth and CPU time spawning a new Object every time it runs. In larger-scale situations, this policy performs well, since large numbers of Actors using the Ability (for example, in a big battle) will only spawn Objects on their first Ability use.

  • Non-Instanced: This is the most efficient instancing policy in all categories. The Ability will not spawn any Object when it runs, and will instead use the Class Default Object. However, this efficiency introduces several restrictions. First, this policy uniquely requires that the Ability is written entirely in C++, as Blueprint Graphs require an Object instance. You can create Blueprint classes of a non-instanced Ability, but only to change the default values of exposed Properties. Further, the Ability must not change member variables or bind Delegates during its execution of the Ability. The Ability also cannot replicate variables or handle RPCs. This should be used only for Abilities that require no internal variable storage (although setting Attributes on the user of the Ability is possible) and don't need to replicate any data. It is especially well-suited to Abilities that run frequently and are used by many characters, such as the basic attack used by units in a large-scale RTS or MOBA title.

Changing the Instancing Policy will change how the Gameplay Ability behaves.  For example, calls to OnAvatarSet, OnGiveAbility, ShouldAbilityRespondToEvent, OnRemoveAbility, and CanActivateAbility can happen without activating an Ability.  If using InstancedPerActor, these calls occur on the instanced Ability (since we instance it immediately upon giving the Ability).  However, Non-Instanced and InstancedPerExecution will receive these calls on their Class Default Object instead since they have no instances at the execution point.

Instancing Policy(实例化策略)
当一个 Gameplay Ability 执行时,通常会生成一个新的该类型的 Object(对象)来追踪其执行过程。由于在某些情况下(例如在 Battle Royale、MOBA、MMO 或 RTS 游戏中上百名玩家与 AI 的战斗场景)Abilities 的执行频率可能非常高,频繁创建 Ability Object 可能会对性能产生负面影响。为了解决这个问题,Ability 提供了三种不同的实例化策略,在效率与功能之间做出权衡。支持的三种实例化类型如下:

Instanced per Execution(每次执行实例化)
每次执行 Ability 时,都会生成该 Ability 的一个新对象副本。其优点在于可以自由使用 Blueprint 图表和成员变量,并且每次执行时所有内容都会重置为默认值。这是最易于实现的实例化策略,适用于不频繁执行的 Ability,因为它开销较大。例如 MOBA 游戏中的“大招”就是一个典型例子,由于通常有较长的冷却时间(60-90 秒),而且能使用大招的角色数量也很有限(大约十个)。相反,用于电脑控制“小兵”的普通攻击能力就不适合,因为“小兵”数量可能成百上千,而且它们会频繁使用普通攻击,从而导致大量对象的快速创建(甚至可能涉及 Replication)。

Instanced per Actor(每个角色实例化一次)
每个 Actor(角色)在第一次执行该 Ability 时会生成一个实例,之后的执行都会复用这个实例。这就要求在每次执行之间清理成员变量,但也可以在多次执行之间保存信息。这种策略非常适合用于 Replication,因为 Ability 拥有一个可复制的对象,能够处理变量同步与 RPC 调用,但不会在每次执行时都浪费带宽和 CPU 去创建新对象。在大规模场景中表现良好,例如一场大型战斗中有大量角色使用某个 Ability,每个角色只在首次使用时实例化一次对象。

Non-Instanced(无实例化)
这是在所有方面性能最优的实例化策略。执行 Ability 时不会生成任何对象,而是直接使用该类的 Class Default Object(类默认对象)。但高效的代价是限制较多:
首先,该策略要求 Ability 必须完全使用 C++ 编写,因为 Blueprint 图表需要实例对象。虽然可以创建 Blueprint 类的非实例化 Ability,但只能用于修改暴露属性的默认值。
此外,该 Ability 在执行期间不得修改成员变量或绑定委托(Delegate),也无法进行变量复制或处理 RPC。
这种策略仅适用于不需要内部变量存储的能力(尽管仍可以设置 Ability 使用者的 Attributes),也不需要任何数据复制。它特别适合那些频繁执行、被大量角色使用的 Ability,例如 RTS 或 MOBA 游戏中单位的普通攻击。

改变 Instancing Policy 会影响 Gameplay Ability 的行为方式。例如,OnAvatarSet、OnGiveAbility、ShouldAbilityRespondToEvent、OnRemoveAbility 和 CanActivateAbility 这些函数调用可以在不激活 Ability 的情况下发生。
如果使用 InstancedPerActor,这些调用会发生在 Ability 的实例上(因为赋予 Ability 时立即实例化)。
但如果使用 Non-InstancedInstancedPerExecution,这些调用会发生在 Class Default Object 上,因为在调用发生时并没有实例存在。

 

Triggering with Gameplay Events

Gameplay Events are data structures that can be passed around to trigger Gameplay Abilities directly, sending a data payload for context, without going through the normal channels. The usual way to do this is by calling Send Gameplay Event To Actor and providing an Actor that implements the IAbilitySystemInterface interface and the contextual information that Gameplay Events require, but it is also possible to call Handle Gameplay Event directly on an Ability System Component. Because this isn't the normal path to calling Gameplay Abilities, context information that the Ability may need will be passed in through the FGameplayEventData data structure. This structure is generic and will not be extended for any specific Gameplay Event or Ability, but should be sufficient for any use case. The polymorphic ContextHandle field will provide support for additional information as needed.

When a Gameplay Ability is triggered by a Gameplay Event, it will not run through the Activate Ability code path, but will instead use Activate Ability From Event, which provides the additional context data as a parameter. Be sure to handle this code path if you want your Ability to respond to Gameplay Events.

Triggering with Gameplay Events(通过 Gameplay Events 触发)
Gameplay Events 是一种可以被传递的数据结构,用于直接触发 Gameplay Abilities,并携带上下文数据载荷,而无需经过常规的触发流程。最常见的方式是调用 Send Gameplay Event To Actor,并传入一个实现了 IAbilitySystemInterface 接口的 Actor 以及 Gameplay Event 所需的上下文信息。但也可以直接调用 Ability System Component 上的 Handle Gameplay Event 方法。

由于这不是触发 Ability 的常规路径,Ability 所需的上下文信息会通过 FGameplayEventData 结构传入。这个结构是通用的,不会针对某个具体的 Gameplay Event 或 Ability 进行扩展,但它设计得足够灵活,可以满足各种使用场景。结构中的 ContextHandle 字段是多态的,可用于传递额外信息。

当一个 Gameplay Ability 是通过 Gameplay Event 被触发时,它不会走标准的 ActivateAbility 代码路径,而是使用 ActivateAbilityFromEvent,该方法会把额外的上下文数据作为参数传入。如果希望你的 Ability 能正确响应 Gameplay Events,务必要处理这条代码路径。

 

 

 

 

 

posted @ 2025-04-13 00:01  sun_dust_shadow  阅读(141)  评论(0)    收藏  举报