ue-gameplay-abilities
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGameplay Ability System (GAS)
Gameplay Ability System (GAS)
You are an expert in Unreal Engine's Gameplay Ability System (GAS).
你是Unreal Engine的Gameplay Ability System (GAS)专家。
Context Check
上下文检查
Before proceeding, read to determine:
.agents/ue-project-context.md- Whether the GameplayAbilities plugin is enabled
- Which actors own the AbilitySystemComponent (PlayerState vs Character)
- The replication mode in use (Minimal, Mixed, Full)
- Any existing AttributeSets or ability base classes
在开始操作前,请阅读以确认:
.agents/ue-project-context.md- GameplayAbilities插件是否已启用
- 哪些Actor拥有AbilitySystemComponent(PlayerState 还是 Character)
- 当前使用的复制模式(Minimal、Mixed、Full)
- 已存在的AttributeSet或能力基类
Information Gathering
信息收集
Ask the developer:
- What type of abilities are needed? (active, passive, triggered, instant)
- What attributes are required? (health, mana, stamina, custom stats)
- Is this multiplayer? If so, which actors carry the ASC?
- Are cooldowns and costs required, or is this a passive/trigger system?
- Do abilities need prediction (local-only feedback before server confirms)?
请向开发者询问以下问题:
- 需要哪种类型的能力?(主动、被动、触发、即时)
- 需要哪些属性?(生命值、法力值、耐力、自定义属性)
- 是否为多人游戏?如果是,哪些Actor承载ASC?
- 是否需要冷却时间和消耗,或者这是一个被动/触发系统?
- 能力是否需要预测(服务器确认前的本地反馈)?
GAS Architecture Overview
GAS架构概述
GAS has three pillars that live on (ASC):
UAbilitySystemComponent| Pillar | Class | Purpose |
|---|---|---|
| Abilities | | Logic for what happens when activated |
| Effects | | Data-driven stat mutations (instant, duration, infinite) |
| Attributes | | Float properties representing character stats |
GameplayTags thread through all three as requirements, grants, and blockers.
GAS有三大核心模块,均依赖(ASC):
UAbilitySystemComponent| 核心模块 | 类 | 用途 |
|---|---|---|
| 能力 | | 定义能力激活时的执行逻辑 |
| 效果 | | 基于数据的属性变更(即时、持续、永久) |
| 属性 | | 代表角色属性的浮点型属性集合 |
GameplayTags贯穿这三大模块,用于实现需求校验、权限授予和逻辑阻断。
GAS Setup
GAS设置
1. Enable the Plugin
1. 启用插件
Enable in Plugins array, then in :
GameplayAbilities.uproject[ProjectName].Build.cscsharp
PublicDependencyModuleNames.AddRange(new string[]
{
"GameplayAbilities", "GameplayTags", "GameplayTasks"
});在的Plugins数组中启用,然后在中添加:
.uprojectGameplayAbilities[ProjectName].Build.cscsharp
PublicDependencyModuleNames.AddRange(new string[]
{
"GameplayAbilities", "GameplayTags", "GameplayTasks"
});2. AbilitySystemComponent Ownership
2. AbilitySystemComponent归属
PlayerState (recommended for multiplayer): ASC persists across respawns because PlayerState
is not destroyed on death. Use this for player characters in networked games.
Character/Pawn: Simpler. Use for AI characters or single-player games where persistence
across respawns is not required.
See for full initialization sequences for both patterns.
references/gas-setup-patterns.mdPlayerState(多人游戏推荐):ASC会在角色重生后保留,因为PlayerState不会在死亡时被销毁。适用于联网游戏中的玩家角色。
Character/Pawn:设置更简单。适用于AI角色或无需跨重生保留状态的单人游戏。
完整的初始化流程请参考中的两种模式实现代码。
references/gas-setup-patterns.md3. IAbilitySystemInterface
3. 实现IAbilitySystemInterface
Every actor that owns or exposes an ASC must implement :
IAbilitySystemInterfacecpp
#include "AbilitySystemInterface.h"
UCLASS()
class AMyCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override
{ return AbilitySystemComponent; }
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
};所有拥有或暴露ASC的Actor必须实现:
IAbilitySystemInterfacecpp
#include "AbilitySystemInterface.h"
UCLASS()
class AMyCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override
{ return AbilitySystemComponent; }
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
};4. Replication Modes
4. 复制模式设置
Set on the ASC after creation (server-side only):
cpp
// In BeginPlay or PossessedBy on the server:
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);| Mode | When to Use |
|---|---|
| AI or non-player actors; no GE replication to simulated proxies |
| Player-controlled characters (owner gets full info, others get minimal) |
| Non-player games or debugging; all GEs replicate to all clients |
仅在服务器端创建ASC后设置复制模式:
cpp
// 在服务器端的BeginPlay或PossessedBy函数中调用:
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);| 模式 | 使用场景 |
|---|---|
| AI或非玩家角色;不向模拟代理复制GameplayEffect |
| 玩家控制角色(拥有者获取完整信息,其他客户端获取最小信息) |
| 非玩家游戏或调试场景;所有GameplayEffect复制到所有客户端 |
5. InitAbilityActorInfo
5. 初始化AbilityActorInfo
Must be called on both server and client after possession. Call in (server)
and (client): .
See for full dual-path code with respawn handling.
PossessedByOnRep_PlayerStateASC->InitAbilityActorInfo(OwnerActor, AvatarActor)references/gas-setup-patterns.md必须在服务器和客户端完成角色控制后调用。在服务器的和客户端的中调用:。完整的包含重生处理的双路径代码请参考。
PossessedByOnRep_PlayerStateASC->InitAbilityActorInfo(OwnerActor, AvatarActor)references/gas-setup-patterns.mdGameplayAbilities
GameplayAbilities
Subclass UGameplayAbility
继承UGameplayAbility
cpp
#include "Abilities/GameplayAbility.h"
UCLASS()
class UMyFireballAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UMyFireballAbility();
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData) override;
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
bool bReplicateEndAbility, bool bWasCancelled) override;
// Ability Tasks — async building blocks for latent abilities:
// UAbilityTask_WaitTargetData — waits for targeting (crosshair/AoE confirm)
// UAbilityTask_WaitGameplayEvent — waits for a GameplayEvent tag (e.g., anim notify)
// UAbilityTask_WaitDelay — simple timer
// UAbilityTask_PlayMontageAndWait — montage with callbacks (see ue-animation-system)
// See references/ability-task-reference.md for full list and custom task pattern.
// CancelAbility — called by CancelAbilitiesWithTag or ASC->CancelAbility(Handle)
// Internally calls EndAbility with bWasCancelled=true. Override to add cleanup:
virtual void CancelAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
bool bReplicateCancelAbility) override;
// Custom activation guard — return false to block activation beyond tag checks
virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, /*...*/) const override;
// Must call Super first. Add custom checks (resource availability, cooldown state).
protected:
UPROPERTY(EditDefaultsOnly, Category = "GAS")
TSubclassOf<UGameplayEffect> DamageEffect;
};cpp
#include "Abilities/GameplayAbility.h"
UCLASS()
class UMyFireballAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UMyFireballAbility();
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData) override;
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
bool bReplicateEndAbility, bool bWasCancelled) override;
// Ability Tasks — 用于实现延迟能力的异步构建块:
// UAbilityTask_WaitTargetData — 等待目标选择(准星/范围确认)
// UAbilityTask_WaitGameplayEvent — 等待GameplayEvent标签(例如动画通知)
// UAbilityTask_WaitDelay — 简单计时器
// UAbilityTask_PlayMontageAndWait — 带回调的动画蒙太奇(参考ue-animation-system)
// 完整列表和自定义任务模式请查看references/ability-task-reference.md。
// CancelAbility — 由CancelAbilitiesWithTag或ASC->CancelAbility(Handle)调用
// 内部会调用bWasCancelled=true的EndAbility。重写该方法以添加清理逻辑:
virtual void CancelAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
bool bReplicateCancelAbility) override;
// 自定义激活校验 — 返回false可在标签检查之外阻断能力激活
virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo, /*...*/) const override;
// 必须先调用Super,再添加自定义检查(资源可用性、冷却状态)。
protected:
UPROPERTY(EditDefaultsOnly, Category = "GAS")
TSubclassOf<UGameplayEffect> DamageEffect;
};ActivateAbility Pattern
激活能力的标准模式
cpp
void UMyFireballAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
// 1. Commit: validates and applies cost + cooldown
if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
{
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
return;
}
// 2. Apply effect / spawn projectile / etc.
FGameplayEffectSpecHandle Spec = MakeOutgoingGameplayEffectSpec(DamageEffect, GetAbilityLevel());
FGameplayAbilityTargetDataHandle TargetData =
UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(
ActorInfo->AvatarActor.Get());
ApplyGameplayEffectSpecToTarget(Handle, ActorInfo, ActivationInfo, Spec, TargetData);
// 3. End (instant abilities end immediately; latent abilities wait for tasks)
EndAbility(Handle, ActorInfo, ActivationInfo, true, false);
}CommitAbilityCommitAbilityCostCommitAbilityCooldowncpp
void UMyFireballAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
// 1. 提交:验证并应用消耗与冷却
if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
{
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
return;
}
// 2. 应用效果/生成投射物等
FGameplayEffectSpecHandle Spec = MakeOutgoingGameplayEffectSpec(DamageEffect, GetAbilityLevel());
FGameplayAbilityTargetDataHandle TargetData =
UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(
ActorInfo->AvatarActor.Get());
ApplyGameplayEffectSpecToTarget(Handle, ActorInfo, ActivationInfo, Spec, TargetData);
// 3. 结束能力(即时能力立即结束;延迟能力需等待任务完成)
EndAbility(Handle, ActorInfo, ActivationInfo, true, false);
}CommitAbilityCommitAbilityCostCommitAbilityCooldownInstancing and Net Execution Policy
实例化与网络执行策略
Set in the ability constructor:
cpp
UMyFireballAbility::UMyFireballAbility()
{
// InstancedPerActor - one instance per actor; cheapest for persistent abilities
// InstancedPerExecution - new instance each activation; safe for concurrency
// NonInstanced - CDO runs the ability; no per-execution state
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
// LocalPredicted - client runs immediately, server validates (player abilities)
// ServerOnly - authority only, no prediction
// LocalOnly - local client only (UI, cosmetic)
// ServerInitiated - server activates, clients run non-authoritative predicted copy
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted;
}在能力的构造函数中设置:
cpp
UMyFireballAbility::UMyFireballAbility()
{
// InstancedPerActor - 每个Actor一个实例;对持久化能力来说性能最优
// InstancedPerExecution - 每次激活创建新实例;并发场景下更安全
// NonInstanced - 使用CDO运行能力;无每次执行的独立状态
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
// LocalPredicted - 客户端立即执行,服务器验证(玩家能力推荐)
// ServerOnly - 仅权威端执行,无预测
// LocalOnly - 仅本地客户端执行(UI、 cosmetic效果)
// ServerInitiated - 服务器激活,客户端运行非权威预测副本
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted;
}Granting and Activating Abilities
授予与激活能力
cpp
// Grant (server/authority only):
FGameplayAbilitySpecHandle Handle = ASC->GiveAbility(
FGameplayAbilitySpec(UMyFireballAbility::StaticClass(), 1 /*Level*/));
ASC->TryActivateAbility(Handle); // by handle
ASC->TryActivateAbilityByClass(UMyFireballAbility::StaticClass()); // by class
ASC->TryActivateAbilitiesByTag( // by tag
FGameplayTagContainer(FGameplayTag::RequestGameplayTag("Ability.Skill.Fireball")));cpp
// 授予能力(仅服务器/权威端可调用):
FGameplayAbilitySpecHandle Handle = ASC->GiveAbility(
FGameplayAbilitySpec(UMyFireballAbility::StaticClass(), 1 /*等级*/));
ASC->TryActivateAbility(Handle); // 通过句柄激活
ASC->TryActivateAbilityByClass(UMyFireballAbility::StaticClass()); // 通过类激活
ASC->TryActivateAbilitiesByTag( // 通过标签激活
FGameplayTagContainer(FGameplayTag::RequestGameplayTag("Ability.Skill.Fireball")));Ability Tags
能力标签配置
Configure in the ability CDO constructor:
cpp
// Tags this ability grants to its owner while active:
ActivationOwnedTags.AddTag(FGameplayTag::RequestGameplayTag("Ability.Active.Casting"));
// Tags that prevent this ability from activating:
ActivationBlockedTags.AddTag(FGameplayTag::RequestGameplayTag("State.Stunned"));
// Cancel other active abilities with these tags on activation:
CancelAbilitiesWithTag.AddTag(FGameplayTag::RequestGameplayTag("Ability.Active.Melee"));在能力的CDO构造函数中配置:
cpp
// 能力激活时授予所有者的标签:
ActivationOwnedTags.AddTag(FGameplayTag::RequestGameplayTag("Ability.Active.Casting"));
// 阻止该能力激活的标签:
ActivationBlockedTags.AddTag(FGameplayTag::RequestGameplayTag("State.Stunned"));
// 激活时会取消其他拥有以下标签的活跃能力:
CancelAbilitiesWithTag.AddTag(FGameplayTag::RequestGameplayTag("Ability.Active.Melee"));GameplayEffects
GameplayEffects
Duration Policies
时长策略
| Policy | Behavior |
|---|---|
| Executes once; modifies attribute base value permanently |
| Active for set duration; uses |
| Active until |
| 策略 | 行为 |
|---|---|
| 执行一次;永久修改属性的基础值 |
| 在设定时长内生效;使用 |
| 持续生效,直到调用 |
Applying Effects
应用效果
cpp
FGameplayEffectContextHandle Ctx = ASC->MakeEffectContext();
FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(UMyDamageEffect::StaticClass(), Level, Ctx);
// SetByCaller: inject runtime magnitude using a tag key
Spec.Data->SetSetByCallerMagnitude(
FGameplayTag::RequestGameplayTag("SetByCaller.Damage"), 75.f);
ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get()); // self
ASC->ApplyGameplayEffectSpecToTarget(*Spec.Data.Get(), TargetASC); // target
ASC->RemoveActiveGameplayEffect(ActiveHandle); // by handle
ASC->RemoveActiveGameplayEffectBySourceEffect(
UMyDamageEffect::StaticClass(), nullptr); // by classSee for stacking (AggregateBySource/AggregateByTarget),
periodic effects (damage over time), (complex modifier logic),
conditional effects, and immunity.
references/gameplay-effect-reference.mdUGameplayEffectExecutionCalculationcpp
FGameplayEffectContextHandle Ctx = ASC->MakeEffectContext();
FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(UMyDamageEffect::StaticClass(), Level, Ctx);
// SetByCaller:使用标签键注入运行时数值
Spec.Data->SetSetByCallerMagnitude(
FGameplayTag::RequestGameplayTag("SetByCaller.Damage"), 75.f);
ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get()); // 应用到自身
ASC->ApplyGameplayEffectSpecToTarget(*Spec.Data.Get(), TargetASC); // 应用到目标
ASC->RemoveActiveGameplayEffect(ActiveHandle); // 通过句柄移除
ASC->RemoveActiveGameplayEffectBySourceEffect(
UMyDamageEffect::StaticClass(), nullptr); // 通过类移除叠加规则(按源/按目标聚合)、周期性效果(持续伤害)、(复杂修改逻辑)、条件效果和免疫设置等内容,请查看。
UGameplayEffectExecutionCalculationreferences/gameplay-effect-reference.mdAttributeSet
AttributeSet
Define Attributes
定义属性
cpp
// MyHealthSet.h
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
// Convenience macro - define in your project headers
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class UMyHealthSet : public UAttributeSet
{
GENERATED_BODY()
public:
UMyHealthSet();
// Called BEFORE any modification - use for clamping current value
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
// Called AFTER instant GE executes - react to changes (death, events)
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Health")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UMyHealthSet, Health)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Health")
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UMyHealthSet, MaxHealth)
protected:
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth);
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
};In the , implement replication and callbacks:
.cppcpp
void UMyHealthSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UMyHealthSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UMyHealthSet, MaxHealth, COND_None, REPNOTIFY_Always);
}
void UMyHealthSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UMyHealthSet, Health, OldHealth);
}
// PreAttributeChange: clamp CURRENT value before any modification
void UMyHealthSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetHealthAttribute())
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
}
// PostGameplayEffectExecute: react AFTER instant GE modifies base value (damage, death)
void UMyHealthSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
if (GetHealth() <= 0.f) { /* trigger death */ }
}
}cpp
// MyHealthSet.h
#include "AttributeSet.h"
#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)
UCLASS()
class UMyHealthSet : public UAttributeSet
{
GENERATED_BODY()
public:
UMyHealthSet();
// 在属性修改前调用 - 用于限制当前值的范围
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
// 即时GameplayEffect执行后调用 - 响应属性变化(死亡、事件触发)
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Health")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UMyHealthSet, Health)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Health")
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UMyHealthSet, MaxHealth)
protected:
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth);
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
};在文件中实现复制与回调逻辑:
.cppcpp
void UMyHealthSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UMyHealthSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UMyHealthSet, MaxHealth, COND_None, REPNOTIFY_Always);
}
void UMyHealthSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UMyHealthSet, Health, OldHealth);
}
// PreAttributeChange: 在任何修改前限制当前值的范围
void UMyHealthSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetHealthAttribute())
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
}
// PostGameplayEffectExecute: 即时GameplayEffect修改基础值后响应(伤害、死亡)
void UMyHealthSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
if (GetHealth() <= 0.f) { /* 触发死亡逻辑 */ }
}
}Register AttributeSet on ASC
在ASC上注册AttributeSet
cpp
// In PlayerState or Character constructor:
// Option 1: CreateDefaultSubobject (auto-registered as subobject)
HealthSet = CreateDefaultSubobject<UMyHealthSet>(TEXT("HealthSet"));
// Option 2: Runtime (authority only) — create and register as subobject:
UMyHealthSet* NewSet = NewObject<UMyHealthSet>(this);
AbilitySystemComponent->AddSpawnedAttribute(NewSet);
// Read attribute value:
float CurrentHealth = AbilitySystemComponent->GetNumericAttribute(
UMyHealthSet::GetHealthAttribute());Multiple AttributeSets: An ASC can host multiple subclasses (e.g.,
+ ), each auto-discovered via subobject enumeration. Never register
two instances of the same class -- the second is silently ignored.
UAttributeSetUHealthSetUOffenseSetcpp
// 在PlayerState或Character的构造函数中:
// 选项1: CreateDefaultSubobject(自动作为子对象注册)
HealthSet = CreateDefaultSubobject<UMyHealthSet>(TEXT("HealthSet"));
// 选项2: 运行时注册(仅权威端)—— 创建并注册为子对象:
UMyHealthSet* NewSet = NewObject<UMyHealthSet>(this);
AbilitySystemComponent->AddSpawnedAttribute(NewSet);
// 读取属性值:
float CurrentHealth = AbilitySystemComponent->GetNumericAttribute(
UMyHealthSet::GetHealthAttribute());多AttributeSet: 一个ASC可以托管多个子类(例如 + ),每个子类会通过子对象枚举自动被发现。不要注册同一类的多个实例——第二个实例会被静默忽略。
UAttributeSetUHealthSetUOffenseSetGameplayTags
GameplayTags
Defining Tags
定义标签
In or via native tags (preferred for code references):
Config/DefaultGameplayTags.inicpp
// MyGameplayTags.h
#include "NativeGameplayTags.h"
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_Fireball)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_State_Stunned)
// MyGameplayTags.cpp
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Ability_Fireball, "Ability.Skill.Fireball", "Fireball ability")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_State_Stunned, "State.Stunned", "Actor is stunned")在中定义,或通过原生标签定义(代码引用时推荐):
Config/DefaultGameplayTags.inicpp
// MyGameplayTags.h
#include "NativeGameplayTags.h"
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_Fireball)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_State_Stunned)
// MyGameplayTags.cpp
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Ability_Fireball, "Ability.Skill.Fireball", "火球术能力")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_State_Stunned, "State.Stunned", "Actor处于眩晕状态")Tag Matching
标签匹配
"A.1".MatchesTag("A") == trueMatchesTagExactcpp
FGameplayTagContainer Tags;
Tags.HasTag(FireballTag); // parent-aware match
Tags.HasTagExact(FireballTag); // exact only
Tags.HasAny(OtherContainer);
Tags.HasAll(OtherContainer);
// Query ASC:
ASC->HasMatchingGameplayTag(TAG_State_Stunned);
ASC->GetOwnedGameplayTags(); // FGameplayTagContainer
// Listen for changes:
ASC->RegisterGameplayTagEvent(TAG_State_Stunned, EGameplayTagEventType::NewOrRemoved)
.AddUObject(this, &AMyCharacter::OnStunnedTagChanged);"A.1".MatchesTag("A") == trueMatchesTagExactcpp
FGameplayTagContainer Tags;
Tags.HasTag(FireballTag); // 支持父标签匹配
Tags.HasTagExact(FireballTag); // 仅完全匹配
Tags.HasAny(OtherContainer);
Tags.HasAll(OtherContainer);
// 查询ASC的标签状态:
ASC->HasMatchingGameplayTag(TAG_State_Stunned);
ASC->GetOwnedGameplayTags(); // 返回FGameplayTagContainer
// 监听标签变化:
ASC->RegisterGameplayTagEvent(TAG_State_Stunned, EGameplayTagEventType::NewOrRemoved)
.AddUObject(this, &AMyCharacter::OnStunnedTagChanged);Loose Tags (Manual, No GE)
松散标签(手动管理,不关联GameplayEffect)
cpp
ASC->AddLooseGameplayTag(TAG_State_Stunned);
ASC->RemoveLooseGameplayTag(TAG_State_Stunned);
// Loose tags are NOT replicated by default. To replicate a loose tag,
// pass EGameplayTagReplicationState::TagOnly as the third argument:
ASC->AddLooseGameplayTag(TAG_State_Buffed, 1, EGameplayTagReplicationState::TagOnly);
ASC->RemoveLooseGameplayTag(TAG_State_Buffed, 1, EGameplayTagReplicationState::TagOnly);cpp
ASC->AddLooseGameplayTag(TAG_State_Stunned);
ASC->RemoveLooseGameplayTag(TAG_State_Stunned);
// 松散标签默认不复制。若要复制松散标签,
// 需将第三个参数设为EGameplayTagReplicationState::TagOnly:
ASC->AddLooseGameplayTag(TAG_State_Buffed, 1, EGameplayTagReplicationState::TagOnly);
ASC->RemoveLooseGameplayTag(TAG_State_Buffed, 1, EGameplayTagReplicationState::TagOnly);GameplayCues
GameplayCues
Cosmetic-only (particles, sounds, decals). Never affect gameplay state. Tag prefix:
GameplayCue.In the GE asset, add entries with and level range.
FGameplayEffectCueGameplayCueTagscpp
// Burst (one-shot):
ASC->ExecuteGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Hit.Fire"),
ASC->MakeEffectContext());
// Persistent (add/remove pair):
ASC->AddGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));
ASC->RemoveGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));
// Poll active state:
bool bActive = ASC->IsGameplayCueActive(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));Cue Notify classes:
- : Persistent/looping. Overrides
AGameplayCueNotify_Actor,OnActive,WhileActive.OnRemove - : Burst/one-shot. Overrides
AGameplayCueNotify_Static.OnExecute
Place cue notify assets in for auto-discovery.
/Game/GAS/GameplayCues/UGameplayCueManager仅用于表现效果(粒子、音效、贴花),绝不能影响游戏状态。标签前缀为
GameplayCue.在GameplayEffect资源中添加条目,配置和等级范围。
FGameplayEffectCueGameplayCueTagscpp
// 一次性触发:
ASC->ExecuteGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Hit.Fire"),
ASC->MakeEffectContext());
// 持久化触发(需成对调用添加/移除):
ASC->AddGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));
ASC->RemoveGameplayCue(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));
// 检查激活状态:
bool bActive = ASC->IsGameplayCueActive(FGameplayTag::RequestGameplayTag("GameplayCue.Buff.Speed"));Cue通知类:
- : 持久化/循环效果。重写
AGameplayCueNotify_Actor、OnActive、WhileActive方法。OnRemove - : 一次性触发效果。重写
AGameplayCueNotify_Static方法。OnExecute
将Cue通知资源放置在目录下,以便自动发现。
/Game/GAS/GameplayCues/UGameplayCueManagerCommon Mistakes and Anti-Patterns
常见错误与反模式
ASC ownership confusion: Implement on the class that owns the ASC
(PlayerState), not just on the Pawn. Otherwise lookups fail.
IAbilitySystemInterfaceUAbilitySystemBlueprintLibraryInitAbilityActorInfo only on server: Clients need it too. Call in (client)
and (server). Skipping client-side init breaks attribute replication on the owning client.
OnRep_PlayerStatePossessedByGEs applied before InitAbilityActorInfo: The ASC is not ready; attributes are not registered.
Always complete init before granting abilities or applying effects.
PreAttributeChange vs PostGameplayEffectExecute: fires on every current-value
change (aggregator updates, buff adds/removes). Use it only to clamp. Use
to react to instant GE base-value execution (damage, death). Never send game events from .
PreAttributeChangePostGameplayEffectExecutePreAttributeChangeForgetting CommitAbility: Without it, the ability runs but consumes no mana and starts no cooldown.
Loose tags not replicated: does not replicate by default. Pass
as the third argument to replicate the tag, or grant
via a GE for fully replicated effect-driven tags.
AddLooseGameplayTagEGameplayTagReplicationState::TagOnlyEffect stacking overflow: Stacks beyond are silently rejected. Use
to inspect the current level before attempting further stack applications.
LimitCountGetCurrentStackCountGAS with AI: AI has no PlayerState. Place the ASC on the AICharacter, call
, set replication mode to .
InitAbilityActorInfo(AICharacter, AICharacter)MinimalHot-joining: Late-joining clients receive active effects via
replication after . Never apply startup GEs in unconditionally
-- server-only, or late joiners double-apply.
FActiveGameplayEffectsContainerInitAbilityActorInfoBeginPlayASC归属混淆:在拥有ASC的类(如PlayerState)上实现,而不仅仅是Pawn。否则的查找会失败。
IAbilitySystemInterfaceUAbilitySystemBlueprintLibrary仅在服务器端初始化AbilityActorInfo:客户端也需要调用该方法。在客户端的和服务器端的中都要调用。跳过客户端初始化会导致拥有者客户端的属性复制失效。
OnRep_PlayerStatePossessedBy在初始化AbilityActorInfo前应用GameplayEffect:此时ASC尚未就绪,属性未完成注册。必须在初始化完成后再授予能力或应用效果。
PreAttributeChange与PostGameplayEffectExecute的误用:会在每次当前值变更时触发(聚合器更新、增益添加/移除)。仅用它来限制数值范围。用于响应即时GameplayEffect对基础值的修改(伤害、死亡)。绝不要在中发送游戏事件。
PreAttributeChangePostGameplayEffectExecutePreAttributeChange忘记调用CommitAbility:如果不调用该方法,能力会正常执行但不会消耗资源也不会启动冷却。
松散标签未复制:默认不复制。若要复制标签,需将第三个参数设为,或通过GameplayEffect授予标签以实现完全复制的效果驱动标签。
AddLooseGameplayTagEGameplayTagReplicationState::TagOnly效果叠加溢出:超过的叠加会被静默拒绝。在尝试叠加前,使用检查当前叠加层数。
LimitCountGetCurrentStackCountAI使用GAS:AI没有PlayerState。将ASC放置在AICharacter上,调用,并将复制模式设为。
InitAbilityActorInfo(AICharacter, AICharacter)Minimal热加入:延迟加入的客户端会在后通过复制获取活跃效果。不要在中无条件应用启动GameplayEffect——仅在服务器端执行,否则延迟加入的客户端会重复应用。
InitAbilityActorInfoFActiveGameplayEffectsContainerBeginPlayReference Files
参考文件
- — Full ASC ownership patterns and initialization sequences for PlayerState and Character owners, multiplayer and single-player
references/gas-setup-patterns.md - — Effect configuration, stacking rules, modifier types, execution calculations, periodic effects, conditional effects
references/gameplay-effect-reference.md - — Common built-in ability tasks and custom task patterns
references/ability-task-reference.md
- — 完整的ASC归属模式和初始化流程,包含PlayerState和Character两种归属场景,覆盖多人和单人游戏
references/gas-setup-patterns.md - — 效果配置、叠加规则、修改器类型、执行计算、周期性效果、条件效果
references/gameplay-effect-reference.md - — 常用内置Ability Task和自定义任务模式
references/ability-task-reference.md
Related Skills
相关技能
- — Component setup and subobject registration
ue-actor-component-architecture - — Replication modes, RPCs, prediction keys
ue-networking-replication - — Montage ability tasks (PlayMontageAndWait)
ue-animation-system - — PlayerState ownership pattern, Pawn/Controller lifecycle
ue-gameplay-framework - — Delegate binding, UPROPERTY macros, TSubclassOf patterns
ue-cpp-foundations
- — 组件设置与子对象注册
ue-actor-component-architecture - — 复制模式、RPC、预测键
ue-networking-replication - — 动画蒙太奇Ability Task(PlayMontageAndWait)
ue-animation-system - — PlayerState归属模式、Pawn/Controller生命周期
ue-gameplay-framework - — 委托绑定、UPROPERTY宏、TSubclassOf模式
ue-cpp-foundations