Gameplay Ability System
Gameplay Ability System
这篇文章这个课程的记录Unreal Engine 5 Gas Top Down RPG

- Ability System Component:控制技能生命周期。
- Attribute Set:数据配置
- Gameplay Ability:技能逻辑
- Ability Task:技能执行在一帧,可以设置不同的回调也就是任务,来响应技能执行。
- Gameplay Effect:技能产生的影响,修改了那些数据。
- Gameplay Cue:技能相关的音效,粒子效果,相机抖动等。
- Gameplay Tag:描述物体的状态或数据,可以用来控制技能的释放等。
Ability System Component

Ability System Component
和Attribute Set
可以放在Pawn
上也可以放在Player State
。他们的区别是Pawn
会在游戏中会被销毁,那么技能系统也就销毁了。
Init Ability Actor Info
当ASC
在不同的宿主上时,初始化的地方各有不同,主要原因是要确保Controller
已经被初始化。

ASC
可以有两种类型的宿主,在初始化ASC
时,使用该函数:
void UAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
- InOwnerActor 逻辑上的宿主
- InAvatarActor 游戏世界里物理宿主
在多人游戏中一般可以这样设置:

EGameplayEffectReplicationMode
Replication | Use Case | Description |
---|---|---|
Full | Single Player | Gameplay Effects are replicated to all clients |
Mixed | Multiplayer, Player-Controlled | Game Effects are replicated to the owning client only. Gameplay Cues and Gameplay Tags replicated to all clients. |
Minimal | Multiplayer, AI-Controlled | Gameplay Effects are NOT replicated. Gameplay Cues and Gameplay Tags replicated to all clients. |
当设置为Mixed
时,ASC
的拥有者必须是Controller
。PlayerState
会自动转换为Controller
。如果是其他的类型,就需要调用SetOwner()
把ASC
设置到Controller
上。
使用蓝图库来获取该组件:
#include "AbilitySystemBlueprintLibrary.h"
UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(AActor* Target);
Attribute Set
使用下面的宏来设置属性函数:
#include "AbilitySystemComponent.h"
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
头文件实列:
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Vital Attributes")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(ThisClass, Health);
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth);
类实列:
void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, Health, COND_None, REPNOTIFY_Always);
}
void UAuraAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, Health, OldHealth);
}
BaseValue vs CurrentValue
一个Attribute
是由两个数值组成的:
BaseValue
:在一段时间内的永久的值(GameplayEffectExecute执行期间)CurrentValue
:BaseValue
+GameplayEffect
的临时修改值
在GameplayEffect Execute
对Atrribute
进行修改时,BaseValue
在这个期间是不做修改的。CurrentValue
是实时在修改的。在Debug中显示的数值一直都是CurrentValue
。
不过GameplayEffect
设置的Scalabe Float
如下图:

BaseValue
最先被修改,之后再是CurrentValue
。其中回调的顺序为:
PreAttributeBaseChange->PreAttributeChange->PostAttributeChange->PostAttributeBaseChange->PostGameplayEffectExecute
使用DataTable初始化
创建 FAttributeMetaData
的DataTable,配置如下:

行的名字为C++中AttributeSet类型名字+属性名字
,然后把这个数据表配置到PlayerSate->Attribute Test->Default Starting Data
上即可。

这种方式并不是良策,常见的初始化属性值:直接对ACS
添加一个初始化的GameplayEffect
。
常用函数
- PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const:
BaseValue
在修改前,调用。 - PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) :
CurrentValue
在修改前,调用。 - PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue):
CurrentValue
在修改后,调用。 - PostAttributeBaseChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) const:
BaseValue
在修改后,调用。 - PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData &Data):在一个
GameplayEffect
执行修改数据之前,调用。
**注意:在PreAttributeChange
函数中对NewValue
进行范围设置,只会影响到当前数据的变化,并不会影响到基础数据,所以需要在PostGameplayEffectExecute
函数中再对基础数据做出范围设置,Epic 推荐在每一次Attribute
被修改后都做一次范围设置,也就是监听UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute)
委托 **
Gameplay Effect

执行规则:
- Instant 一次
- Has Duration 一段时间
- Infinite 无限次
Periodic Gameplay Effects

在一段时间内定期修改基础数值
Stacking
Aggregate by Soucre

Aggregate by Soucre

Modifiers Magnitdue
更改的操作有4种:
Operation | Description |
---|---|
Add | 在指定的Attribute 上加上配置的数值,使用负数来实现减法。 |
Multiply | Multiplies the result to the Modifier's specified Attribute . |
Divide | Divides the result against the Modifier's specified Attribute . |
Override | Overrides the Modifier's specified Attribute with the result. |
有4种修改器:
Modifier Type | Description |
---|---|
Scalable Float | FScalableFloats are a structure that can point to a Data Table that has the variables as rows and levels as columns. The Scalable Floats will automatically read the value of the specified table row at the ability's current level (or different level if overriden on the GameplayEffectSpec ). This value can further be manipulated by a coefficient. If no Data Table/Row is specified, it treats the value as a 1 so the coefficient can be used to hard code in a single value at all levels. ![]() |
Attribute Based | Attribute Based Modifiers take the CurrentValue or BaseValue of a backing Attribute on the Source (who created the GameplayEffectSpec ) or Target (who received the GameplayEffectSpec ) and further modifies it with a coefficient and pre and post coefficient additions. Snapshotting means the backing Attribute is captured when the GameplayEffectSpec is created whereas no snapshotting means the Attribute is captured when the GameplayEffectSpec is applied. |
Custom Calculation Class | Custom Calculation Class provides the most flexibility for complex Modifiers . This Modifier takes a ModifierMagnitudeCalculation class and can further manipulate the resulting float value with a coefficient and pre and post coefficient additions. |
Set By Caller | SetByCaller Modifiers are values that are set outside of the GameplayEffect at runtime by the ability or whoever made the GameplayEffectSpec on the GameplayEffectSpec . For example, you would use a SetByCaller if you want to set the damage to be based on how long the player held down a button to charge the ability. SetByCallers are essentially TMap<FGameplayTag, float> that live on the GameplayEffectSpec . The Modifier is just telling the Aggregator to look for a SetByCaller value associated with the supplied GameplayTag . The SetByCallers used by Modifiers can only use the GameplayTag version of the concept. The FName version is disabled here. If the Modifier is set to SetByCaller but a SetByCaller with the correct GameplayTag does not exist on the GameplayEffectSpec , the game will throw a runtime error and return a value of 0. This might cause issues in the case of a Divide operation. See SetByCallers for more information on how to use SetByCallers . |
Modifiers Order of Operation
执行顺序是从上往下。



Attribute Base Modifier Coefficeient
与预先处理基础数据。

Custom Calculation

Execution Calculation


Set By Caller
使用UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(SpecHandle, GameplayTags.Damage, 50.f);
函数来设置Tag
对于的数值。
Tags
GameplayEffect中的Tag配置:

Category | Description |
---|---|
Gameplay Effect Asset Tags | Tags that the GameplayEffect has. They do not do any function on their own and serve only the purpose of describing the GameplayEffect . |
Granted Tags | Tags that live on the GameplayEffect but are also given to the ASC that the GameplayEffect is applied to. They are removed from the ASC when the GameplayEffect is removed. This only works for Duration and Infinite GameplayEffects . |
Ongoing Tag Requirements | Once applied, these tags determine whether the GameplayEffect is on or off. A GameplayEffect can be off and still be applied. If a GameplayEffect is off due to failing the Ongoing Tag Requirements, but the requirements are then met, the GameplayEffect will turn on again and reapply its modifiers. This only works for Duration and Infinite GameplayEffects . |
Application Tag Requirements | Tags on the Target that determine if a GameplayEffect can be applied to the Target. If these requirements are not met, the GameplayEffect is not applied. |
Remove Gameplay Effects with Tags | GameplayEffects on the Target that have any of these tags in their Asset Tags or Granted Tags will be removed from the Target when this GameplayEffect is successfully applied. |
以上设置在5.3之前还是有的,在5.3中是把上面的属性设置到组件里如图:

Gameplay Effect | Component Description |
---|---|
UChanceToApplyGameplayEffectComponent | 应用Gameplay效果的率。 |
UBlockAbilityTagsGameplayEffectComponent | 根据所有者Gameplay效果目标Actor的Gameplay标签,进行Gameplay技能激活阻止处理。 |
UAssetTagsGameplayEffectComponent | Gameplay效果资产拥有的标签。这些标签 不会 转移到Actor。 |
UAdditionalEffectsGameplayEffectComponent | 添加尝试在特定条件下激活(或任何条件下都不激活)的其他Gameplay效果。 |
UTargetTagsGameplayEffectComponent | 将标签授予Gameplay效果的目标(有时指所有者),在效果结束时会自动取消掉该标签。只在Duration 模式下,生效且在开启Stack 限制时,只会添加一此在对象上。 |
UTargetTagRequirementsGameplayEffectComponent | 指定如果此GE须应用或继续执行,目标(Gameplay效果的拥有者)必须具备的标签要求。 |
URemoveOtherGameplayEffectComponent | 基于某些条件移除其他Gameplay效果。 |
UCustomCanApplyGameplayEffectComponent | 处理CustomApplicationRequirement函数的配置,以查看是否应该应用此Gameplay效果。 |
UImmunityGameplayEffectComponent | 免疫会阻止其他GameplayEffectSpecs的应用。 |
GameplayEffectContext
可以自定义FGameplayEffectContext
,用来存储技能中使用到的一些数据。不过一定需要重写以下两个东西:
/** Returns the actual struct used for serialization,subclasses must override this! */
virtual UScriptStruct* GetScriptStruct() const override
{
return FAuraGameplayEffectContext::StaticStruct();
}
template <>
struct TStructOpsTypeTraits<FAuraGameplayEffectContext> : public TStructOpsTypeTraitsBase2<FAuraGameplayEffectContext>
{
enum
{
WithNetSerializer = true,
WithCopy = true // Necessary so that TSharedPtr<FHitResult> Data is copied around
};
};
如果还需要网络同步的话,需要重写:
/** Custom serialization, subclasses must override this */
virtual bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) override;
Gameplay Ability


可以简单总结为以下几点:
- 一定定义了技能或能力的类
- 必须被生成
- 在服务器上生成
Spec
复制给对应的客户端
- 使用
Activated
方法来使用 - 激活需要消耗,也有冷却
- 异步执行
- 同一时间激活多个
- 技能任务
- 异步表现不同操作
Tags
Gameplay Tag | Description |
---|---|
Ability Tags | 该技能拥有的标签 |
Cancel Abilities with Tag | 激活该技能时,取消带有这些标签的所有技能 |
Block Abilities with Tag | 激活该技能时,锁定带有这些标签的所有技能 |
Activation Owned Tags | 激活该技能时,把这些标签赋予激活对象。在AbilitySystemGlobals中开启ReplicateActivationOwnedTags,这些标签会被复制。 |
Activation Required Tags | 该技能只能在拥有这些标签的Actor/Component上激活 |
Activation Blocked Tags | 该技能被锁定,如果激活对象Actor/Component上有这些标签 |
Source Required Tags | 激活源Actor/Component上有所有这些标签才能激活这个技能 |
Source Blocked Tags | 激活源Actor/Component上有所有这些标签,该技能被锁定 |
Target Required Tags | 激活目标Actor/Component上有所有这些标签才能激活这个技能 |
Target Blocked Tags | 激活目标Actor/Component上有所有这些标签,该技能被锁定 |
Instancing Policy
Instancing Policy | Description | Details |
---|---|---|
Instanced Per Actor | 一个单例在能力被创建时,每一次激活复用 | 可以存储持久数据。每次激活,变量必须手动重置。 |
Instanced Per Execution | 每激活一次,创建一个实例 | 不能存储两次激活之间的数据。 |
Non-Instanced | 只有默认类对象,没有实例,静态类 | 不能存储状态,不能绑定回调任务。 |
Net Execution Policy
Net Execution Policy | Description |
---|---|
Local Only | 只在客户端上运行,不在服务器运行。 |
Local Predicted | 先在客户端上激活,然后在服务器上。本地使用预测。服务器可以回滚非法改变 |
Server Only | 只在服务器上运行 |
Server Initiated | 现在服务器上运行,然后在对于客户端上执行 |
Things Not to Use

Enhanced Input
- Input Action are bound to inputs via the Input Mapping Context.
- We can decide how to activate abilities in response to inputs.
- Lyra provides one example
- We'll use a similar approach (though less complicated)
- Data Driven
- Change Input-to-Ability mappings at runtime
Cost
在GA
面板上设置特定的GE
即可。

在GE
中设置需要扣除的属性即可。需要在技能激活时调用CommitAbilityCost
执行扣除逻辑。
Cooldown
在GA
面板上设置特定的GE
即可。

该GE
需要特殊设置两个参数:
- Duration Policy:改为时间持续,这里的时间即为CD时间。
- 设置专属冷却
Tag
,这个标签是用来判断冷却是否结束。
Ability Task

Target Data
如果需要使用这个数据,需要调用初始化:
// This is required to use Target Data
UAbilitySystemGlobals::Get().InitGlobalData();

使用ServerSetReplicatedTargetData()
把数据复制到服务器

Wait Gameplay Event

如果技能不是每次激活生成新的对象,最好把OnlyTriggerOnce
选择上,防止多次触发。
Gameplay Cue
Gameplay Tag

可以多出使用Tag:
- Inputs
- Abilities
- Attributes
- Damage Types
- Buffs/Debuffs
- Messages
- Data
- Anything you want!
管理所有Tags:
- 存在
Config/DefaultGameplayTags.ini
文件中
-Edit->Project Setting->GameplayTags
- 使用
DataTable
创建GameplayTagTableRow
数据表,需要配置到项目设置中的Gameplay Tag Table List
如果直接在编辑器下定义,需要在C++中使用,可以使用这个API:
FGameplayTag::RequestGameplayTag("Ability.Attack", false)
在c++
中声明自定义Tag,使用UGameplayTagsManager::Get().AddNativeGameplayTag()
:
// 头文件
#include "GameplayTagContainer.h"
struct FAuraGameplayTags
{
public:
static const FAuraGameplayTags& Get()
{
return GameplayTags;
}
static void InitNativeGameplayTags();
public:
FGameplayTag Attributes_Primary_Strength;
private:
static FAuraGameplayTags GameplayTags;
};
//源文件
#include "GameplayTagsManager.h"
FAuraGameplayTags FAuraGameplayTags::GameplayTags;
void FAuraGameplayTags::InitNativeGameplayTags()
{
GameplayTags.Attributes_Primary_Strength = UGameplayTagsManager::Get().AddNativeGameplayTag(FName("Attributes.Primary.Strength"), FString("Test Des."));
}
在c++中最简单的方式定义:
// 放在头文件其他模块可用
UE_DEFINE_GAMEPLAY_TAG(TagName,"Tag");
// 放在源文件中独立存在
UE_DEFINE_GAMEPLAY_TAG_STATIC(TagName,"Tag");
Prediction

如果客户端使用一个技能,向服务器请求,然后服务器确认给客户端。这里的时间差就会很久。

预测就是,客户端先执行需要使用的技能,同时向服务器发送。服务器在验证后,如果正常就不需要做什么,如果不正常需要取消客户端的技能操作。
GAS Automatically Predicts
- Gameplay Ability Activation
- Triggered Events
- Gameplay Effect Application
- Attribute Modifiers (not Execution Calculations)
- GameplayTag Modification
- Gameplay Cue Events
- From within a predicted Gameplay Ability
- Their own Events
- Montages
- Movement (UCharacterMovement)
GAS Does NOT Predict
- Gameplay Effect Removal
- Gameplay Effect Periodic Effects
Prediction Key

Ability Activation


Gameplay Effects Prediction
- Side effects
- Only applied on Clients if:
- There is a valid prediction key
- The following are predicted:
- Attribute Modifications
- Gameplay Tag Modifcations
- Gameplay Cues
- When the FActiveGameplayEffect is created
- Stores the Prediction key (Active Gameplay Effect)
- On the server, it gets the same key
- FActiveGameplayEffect is replicated
- Client checks the key
- If they match, then "OnApplied" logic doesn't need to be done

More Info
- GameplayPrediction.h
Replication Mode
Replication Mode | Use Case | Description |
---|---|---|
Full | Single Player | Gameplay Effects are replicated to all clients |
Mixed | Multiplayer,Player-Controlled | Gameplay Effects are replicated to the owning client only. Gameplay Cues and Gameplay Tags replicated to all clients. |
Minimal | Multiplayer,AI-Controlled | GamePlay Effects are not replicated. Gameplay Cues and Gameplay Tags replicated to all clients. |
Saving Progress

Debug
调试命令:ShowDebug AbilitySystem
可以使用插件GASAttachEditor
。可以看到角色的技能和Tag等信息。
Reference
https://docs.unrealengine.com/5.0/en-US/gameplay-ability-system-for-unreal-engine/