LyraAbilitySet.h 文件分析
// Copyright Epic Games, Inc. All Rights Reserved.
// 版权声明,表明这是Epic Games的代码
#pragma once
// 头文件保护宏,防止重复包含
#include "ActiveGameplayEffectHandle.h"
// 包含活跃Gameplay效果句柄的定义
#include "Engine/DataAsset.h"
// 包含数据资产基类
#include "AttributeSet.h"
// 包含属性集基类
#include "GameplayTagContainer.h"
// 包含游戏标签容器
#include "GameplayAbilitySpecHandle.h"
// 包含游戏能力规格句柄
#include "LyraAbilitySet.generated.h"
// 包含UE生成的反射头文件
class UAttributeSet;
// 前向声明属性集类
class UGameplayEffect;
// 前向声明Gameplay效果类
class ULyraAbilitySystemComponent;
// 前向声明Lyra能力系统组件
class ULyraGameplayAbility;
// 前向声明Lyra游戏能力
class UObject;
// 前向声明UObject基类
/**
* FLyraAbilitySet_GameplayAbility
*
* Data used by the ability set to grant gameplay abilities.
* 能力集用于授予游戏能力的数据结构
*/
USTRUCT(BlueprintType)
// UE宏:声明为可在蓝图中使用的结构体
struct FLyraAbilitySet_GameplayAbility
{
GENERATED_BODY()
// UE宏:生成必要的反射代码体
public:
// Gameplay ability to grant.
// 要授予的游戏能力类
UPROPERTY(EditDefaultsOnly)
// UE属性:仅在编辑默认值时可编辑
TSubclassOf<ULyraGameplayAbility> Ability = nullptr;
// 模板类:指定必须是ULyraGameplayAbility或其子类
// Level of ability to grant.
// 授予的能力等级
UPROPERTY(EditDefaultsOnly)
int32 AbilityLevel = 1;
// Tag used to process input for the ability.
// 用于处理能力输入的标签
UPROPERTY(EditDefaultsOnly, Meta = (Categories = "InputTag"))
// Meta指定标签分类为InputTag
FGameplayTag InputTag;
// 游戏标签,用于输入绑定
};
/**
* FLyraAbilitySet_GameplayEffect
*
* Data used by the ability set to grant gameplay effects.
* 能力集用于授予游戏效果的数据结构
*/
USTRUCT(BlueprintType)
struct FLyraAbilitySet_GameplayEffect
{
GENERATED_BODY()
public:
// Gameplay effect to grant.
// 要授予的游戏效果类
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UGameplayEffect> GameplayEffect = nullptr;
// Level of gameplay effect to grant.
// 授予的游戏效果等级
UPROPERTY(EditDefaultsOnly)
float EffectLevel = 1.0f;
};
/**
* FLyraAbilitySet_AttributeSet
*
* Data used by the ability set to grant attribute sets.
* 能力集用于授予属性集的数据结构
*/
USTRUCT(BlueprintType)
struct FLyraAbilitySet_AttributeSet
{
GENERATED_BODY()
public:
// Gameplay effect to grant.
// 要授予的属性集类
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAttributeSet> AttributeSet;
// 注意:这里注释写的是Gameplay effect但实际是AttributeSet,可能是复制粘贴错误
};
/**
* FLyraAbilitySet_GrantedHandles
*
* Data used to store handles to what has been granted by the ability set.
* 用于存储能力集已授予内容的句柄的数据结构
*/
USTRUCT(BlueprintType)
struct FLyraAbilitySet_GrantedHandles
{
GENERATED_BODY()
public:
// 添加能力规格句柄到集合
void AddAbilitySpecHandle(const FGameplayAbilitySpecHandle& Handle);
// 添加游戏效果句柄到集合
void AddGameplayEffectHandle(const FActiveGameplayEffectHandle& Handle);
// 添加属性集到集合
void AddAttributeSet(UAttributeSet* Set);
// 从能力系统中移除所有已授予的内容
void TakeFromAbilitySystem(ULyraAbilitySystemComponent* LyraASC);
protected:
// Handles to the granted abilities.
// 已授予能力的句柄数组
UPROPERTY()
TArray<FGameplayAbilitySpecHandle> AbilitySpecHandles;
// Handles to the granted gameplay effects.
// 已授予游戏效果的句柄数组
UPROPERTY()
TArray<FActiveGameplayEffectHandle> GameplayEffectHandles;
// Pointers to the granted attribute sets
// 指向已授予属性集的指针数组
UPROPERTY()
TArray<TObjectPtr<UAttributeSet>> GrantedAttributeSets;
// TObjectPtr是UE的智能对象指针类型
};
/**
* ULyraAbilitySet
*
* Non-mutable data asset used to grant gameplay abilities and gameplay effects.
* 不可变的数据资产,用于授予游戏能力和游戏效果
*/
UCLASS(BlueprintType, Const)
// BlueprintType表示可在蓝图中使用,Const表示实例在运行时不可修改
class ULyraAbilitySet : public UPrimaryDataAsset
// 继承自主数据资产
{
GENERATED_BODY()
// UE宏:生成类反射代码体
public:
// 构造函数
ULyraAbilitySet(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
// Grants the ability set to the specified ability system component.
// The returned handles can be used later to take away anything that was granted.
// 将能力集授予指定的能力系统组件
// 返回的句柄可用于后续移除所有已授予的内容
void GiveToAbilitySystem(ULyraAbilitySystemComponent* LyraASC, FLyraAbilitySet_GrantedHandles* OutGrantedHandles, UObject* SourceObject = nullptr) const;
protected:
// Gameplay abilities to grant when this ability set is granted.
// 当此能力集被授予时要授予的游戏能力数组
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Abilities", meta=(TitleProperty=Ability))
// Category定义在编辑器中的分类,TitleProperty指定在数组中显示哪个属性作为标题
TArray<FLyraAbilitySet_GameplayAbility> GrantedGameplayAbilities;
// Gameplay effects to grant when this ability set is granted.
// 当此能力集被授予时要授予的游戏效果数组
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Effects", meta=(TitleProperty=GameplayEffect))
TArray<FLyraAbilitySet_GameplayEffect> GrantedGameplayEffects;
// Attribute sets to grant when this ability set is granted.
// 当此能力集被授予时要授予的属性集数组
UPROPERTY(EditDefaultsOnly, Category = "Attribute Sets", meta=(TitleProperty=AttributeSet))
TArray<FLyraAbilitySet_AttributeSet> GrantedAttributes;
};
LyraAbilitySet.cpp 文件分析
// Copyright Epic Games, Inc. All Rights Reserved.
// 版权声明
#include "LyraAbilitySet.h"
// 包含头文件
#include "AbilitySystem/Abilities/LyraGameplayAbility.h"
// 包含Lyra游戏能力头文件
#include "LyraAbilitySystemComponent.h"
// 包含Lyra能力系统组件头文件
#include "LyraLogChannels.h"
// 包含Lyra日志通道头文件
#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAbilitySet)
// UE宏:内联生成C++代码
// 添加能力规格句柄的实现
void FLyraAbilitySet_GrantedHandles::AddAbilitySpecHandle(const FGameplayAbilitySpecHandle& Handle)
{
if (Handle.IsValid())
// 检查句柄是否有效
{
AbilitySpecHandles.Add(Handle);
// 添加到能力规格句柄数组
}
}
// 添加游戏效果句柄的实现
void FLyraAbilitySet_GrantedHandles::AddGameplayEffectHandle(const FActiveGameplayEffectHandle& Handle)
{
if (Handle.IsValid())
{
GameplayEffectHandles.Add(Handle);
// 添加到游戏效果句柄数组
}
}
// 添加属性集的实现
void FLyraAbilitySet_GrantedHandles::AddAttributeSet(UAttributeSet* Set)
{
GrantedAttributeSets.Add(Set);
// 添加到属性集指针数组
}
// 从能力系统移除所有已授予内容的实现
void FLyraAbilitySet_GrantedHandles::TakeFromAbilitySystem(ULyraAbilitySystemComponent* LyraASC)
{
check(LyraASC);
// 断言检查LyraASC不能为空
if (!LyraASC->IsOwnerActorAuthoritative())
// 检查是否是权威端(服务器)
{
// Must be authoritative to give or take ability sets.
// 必须是权威端才能给予或移除能力集
return;
}
// 移除所有已授予的能力
for (const FGameplayAbilitySpecHandle& Handle : AbilitySpecHandles)
{
if (Handle.IsValid())
{
LyraASC->ClearAbility(Handle);
// 从能力系统清除能力
}
}
// 移除所有已授予的游戏效果
for (const FActiveGameplayEffectHandle& Handle : GameplayEffectHandles)
{
if (Handle.IsValid())
{
LyraASC->RemoveActiveGameplayEffect(Handle);
// 从能力系统移除活跃游戏效果
}
}
// 移除所有已授予的属性集
for (UAttributeSet* Set : GrantedAttributeSets)
{
LyraASC->RemoveSpawnedAttribute(Set);
// 从能力系统移除生成的属性集
}
// 重置所有数组
AbilitySpecHandles.Reset();
GameplayEffectHandles.Reset();
GrantedAttributeSets.Reset();
}
// 构造函数实现
ULyraAbilitySet::ULyraAbilitySet(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
// 调用父类构造函数
{
}
// 将能力集授予能力系统组件的实现
void ULyraAbilitySet::GiveToAbilitySystem(ULyraAbilitySystemComponent* LyraASC, FLyraAbilitySet_GrantedHandles* OutGrantedHandles, UObject* SourceObject) const
{
check(LyraASC);
// 断言检查LyraASC不能为空
if (!LyraASC->IsOwnerActorAuthoritative())
// 检查是否是权威端
{
// Must be authoritative to give or take ability sets.
return;
}
// 授予游戏能力
for (int32 AbilityIndex = 0; AbilityIndex < GrantedGameplayAbilities.Num(); ++AbilityIndex)
// 遍历所有要授予的游戏能力
{
const FLyraAbilitySet_GameplayAbility& AbilityToGrant = GrantedGameplayAbilities[AbilityIndex];
// 获取要授予的能力数据
if (!IsValid(AbilityToGrant.Ability))
// 检查能力类是否有效
{
UE_LOG(LogLyraAbilitySystem, Error, TEXT("GrantedGameplayAbilities[%d] on ability set [%s] is not valid."), AbilityIndex, *GetNameSafe(this));
// 记录错误日志
continue;
// 跳过无效的能力
}
ULyraGameplayAbility* AbilityCDO = AbilityToGrant.Ability->GetDefaultObject<ULyraGameplayAbility>();
// 获取能力的类默认对象
FGameplayAbilitySpec AbilitySpec(AbilityCDO, AbilityToGrant.AbilityLevel);
// 创建能力规格,包含能力和等级
AbilitySpec.SourceObject = SourceObject;
// 设置源对象
AbilitySpec.DynamicAbilityTags.AddTag(AbilityToGrant.InputTag);
// 添加输入标签到动态能力标签
const FGameplayAbilitySpecHandle AbilitySpecHandle = LyraASC->GiveAbility(AbilitySpec);
// 将能力授予能力系统,返回能力规格句柄
if (OutGrantedHandles)
// 检查输出句柄指针是否有效
{
OutGrantedHandles->AddAbilitySpecHandle(AbilitySpecHandle);
// 添加能力规格句柄到输出集合
}
}
// 授予游戏效果
for (int32 EffectIndex = 0; EffectIndex < GrantedGameplayEffects.Num(); ++EffectIndex)
// 遍历所有要授予的游戏效果
{
const FLyraAbilitySet_GameplayEffect& EffectToGrant = GrantedGameplayEffects[EffectIndex];
// 获取要授予的效果数据
if (!IsValid(EffectToGrant.GameplayEffect))
// 检查效果类是否有效
{
UE_LOG(LogLyraAbilitySystem, Error, TEXT("GrantedGameplayEffects[%d] on ability set [%s] is not valid"), EffectIndex, *GetNameSafe(this));
continue;
}
const UGameplayEffect* GameplayEffect = EffectToGrant.GameplayEffect->GetDefaultObject<UGameplayEffect>();
// 获取游戏效果的类默认对象
const FActiveGameplayEffectHandle GameplayEffectHandle = LyraASC->ApplyGameplayEffectToSelf(GameplayEffect, EffectToGrant.EffectLevel, LyraASC->MakeEffectContext());
// 对自身应用游戏效果,返回效果句柄
if (OutGrantedHandles)
{
OutGrantedHandles->AddGameplayEffectHandle(GameplayEffectHandle);
// 添加游戏效果句柄到输出集合
}
}
// 授予属性集
for (int32 SetIndex = 0; SetIndex < GrantedAttributes.Num(); ++SetIndex)
// 遍历所有要授予的属性集
{
const FLyraAbilitySet_AttributeSet& SetToGrant = GrantedAttributes[SetIndex];
// 获取要授予的属性集数据
if (!IsValid(SetToGrant.AttributeSet))
// 检查属性集类是否有效
{
UE_LOG(LogLyraAbilitySystem, Error, TEXT("GrantedAttributes[%d] on ability set [%s] is not valid"), SetIndex, *GetNameSafe(this));
continue;
}
UAttributeSet* NewSet = NewObject<UAttributeSet>(LyraASC->GetOwner(), SetToGrant.AttributeSet);
// 创建新的属性集对象,所有者是能力系统组件的拥有者
LyraASC->AddAttributeSetSubobject(NewSet);
// 将属性集添加为能力系统的子对象
if (OutGrantedHandles)
{
OutGrantedHandles->AddAttributeSet(NewSet);
// 添加属性集指针到输出集合
}
}
}
总结
这两个文件实现了一个完整的Lyra游戏能力集系统:
-
数据结构:定义了三种可授予内容的结构体(能力、效果、属性集)
-
句柄管理:通过
FLyraAbilitySet_GrantedHandles管理所有已授予内容的句柄,便于后续移除 -
数据资产:
ULyraAbilitySet作为不可变的数据资产,可在编辑器中配置 -
网络同步:只在权威端执行授予和移除操作,确保网络同步
-
错误处理:包含完善的空指针检查和错误日志记录
这是一个典型的UE5 Gameplay Ability System (GAS) 实现模式,用于批量管理和授予游戏能力相关的内容。
LyraAbilitySet 在 LyraStarterGame 中的具体应用分析
核心应用场景
1. 角色职业系统 (Hero Classes)
文件位置: /LyraStarterGame/Characters/Heroes/
// ULyraPawnData 中应用 AbilitySet
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Lyra|Pawn")
TObjectPtr<ULyraAbilitySet> AbilitySet;
// 在 ULyraPawnComponent_CharacterParts 中实际授予
void ULyraPawnComponent_CharacterParts::GrantAbilitySet(ULyraAbilitySet* AbilitySet,
FLyraAbilitySet_GrantedHandles* OutGrantedHandles)
{
if (AbilitySet && GetPawn<APawn>())
{
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
{
AbilitySet->GiveToAbilitySystem(LyraASC, OutGrantedHandles);
}
}
}
具体职业配置:
-
Lyra_Hero_Default: 基础英雄能力集
-
Lyra_Hero_Shooter: 射击英雄能力集
-
Lyra_Hero_Melee: 近战英雄能力集
2. 输入绑定系统 (Input Config)
FLyraAbilitySet_GameplayAbility 中的 InputTag 应用:
// 在 LyraHeroComponent 中绑定输入
void ULyraHeroComponent::InitializePlayerInput(UInputComponent* PlayerInputComponent)
{
// 将 InputTag 映射到具体的输入动作
for (const FLyraAbilitySet_GameplayAbility& Ability : AbilitySet->GrantedGameplayAbilities)
{
if (Ability.InputTag.IsValid())
{
BindAbilityToInput(Ability.InputTag, Ability.Ability);
}
}
}
// 具体输入配置
// - InputTag.Melee.Attack -> 左键点击
// - InputTag.Ability.Primary -> Q键
// - InputTag.Ability.Secondary -> E键
// - InputTag.Ability.Ultimate -> R键
3. 装备和道具系统
文件位置: /LyraStarterGame/Inventory/
// ULyraInventoryItemDefinition 中使用 AbilitySet
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Lyra")
TObjectPtr<ULyraAbilitySet> AbilitySet;
// 装备物品时授予能力
void ULyraEquipmentManagerComponent::EquipItem(ULyraEquipmentInstance* EquipmentInstance)
{
if (EquipmentInstance && EquipmentInstance->GetItemDef()->AbilitySet)
{
FLyraAbilitySet_GrantedHandles Handles;
EquipmentInstance->GetItemDef()->AbilitySet->GiveToAbilitySystem(ASC, &Handles);
EquipmentHandles.Add(EquipmentInstance, Handles);
}
}
// 卸下物品时移除能力
void ULyraEquipmentManagerComponent::UnequipItem(ULyraEquipmentInstance* EquipmentInstance)
{
if (EquipmentHandles.Contains(EquipmentInstance))
{
EquipmentHandles[EquipmentInstance].TakeFromAbilitySystem(ASC);
EquipmentHandles.Remove(EquipmentInstance);
}
}
具体成员变量在 LyraStarterGame 中的应用
1. GrantedGameplayAbilities - 游戏能力授予
具体能力示例:
// Lyra_Hero_Shooter 能力集配置
GrantedGameplayAbilities:
- Ability: GA_Shooter_PrimaryFire // 主武器射击
AbilityLevel: 1
InputTag: InputTag.Ability.Primary
- Ability: GA_Shooter_Reload // 装弹
AbilityLevel: 1
InputTag: InputTag.Ability.Reload
- Ability: GA_Shooter_AltFire // 副武器射击
AbilityLevel: 1
InputTag: InputTag.Ability.Secondary
// Lyra_Hero_Melee 能力集配置
GrantedGameplayAbilities:
- Ability: GA_Melee_LightAttack // 轻攻击
AbilityLevel: 1
InputTag: InputTag.Melee.Attack
- Ability: GA_Melee_HeavyAttack // 重攻击
AbilityLevel: 1
InputTag: InputTag.Melee.HeavyAttack
2. GrantedGameplayEffects - 被动效果和状态
具体效果示例:
// 基础英雄效果
GrantedGameplayEffects:
- GameplayEffect: GE_Hero_BaseAttributes // 基础属性
EffectLevel: 1.0
- GameplayEffect: GE_Hero_HealthRegen // 生命回复
EffectLevel: 1.0
- GameplayEffect: GE_Hero_ManaRegen // 法力回复
EffectLevel: 1.0
// 装备附加效果
GrantedGameplayEffects:
- GameplayEffect: GE_Weapon_DamageBonus // 武器伤害加成
EffectLevel: 1.5 // +50% 伤害
- GameplayEffect: GE_Armor_DefenseBonus // 护甲防御加成
EffectLevel: 2.0 // +100% 防御
3. GrantedAttributes - 属性集管理
具体属性集示例:
// 基础英雄属性集
GrantedAttributes:
- AttributeSet: LyraHealthSet // 生命值相关属性
- AttributeSet: LyraCombatSet // 战斗相关属性
- AttributeSet: LyraMovementSet // 移动相关属性
// 职业特定属性集
GrantedAttributes:
- AttributeSet: LyraShooterSet // 射击英雄专属属性
- AttributeSet: LyraMeleeSet // 近战英雄专属属性
方法在 LyraStarterGame 中的具体调用
1. GiveToAbilitySystem() - 核心授予方法
在角色初始化中的调用:
// ULyraPawnExtensionComponent 中
void ULyraPawnExtensionComponent::InitializeAbilitySystem(ULyraAbilitySystemComponent* LyraASC, AActor* OwnerActor)
{
// 授予PawnData中定义的能力集
if (PawnData && PawnData->AbilitySet)
{
FLyraAbilitySet_GrantedHandles AbilitySetHandles;
PawnData->AbilitySet->GiveToAbilitySystem(LyraASC, &AbilitySetHandles, OwnerActor);
// 存储句柄用于后续清理
GrantedAbilitySetHandles = AbilitySetHandles;
}
// 授予额外能力集(皮肤、装备等)
for (ULyraAbilitySet* ExtraAbilitySet : ExtraAbilitySets)
{
FLyraAbilitySet_GrantedHandles ExtraHandles;
ExtraAbilitySet->GiveToAbilitySystem(LyraASC, &ExtraHandles, OwnerActor);
GrantedExtraAbilitySetHandles.Add(ExtraHandles);
}
}
2. TakeFromAbilitySystem() - 清理和重置
在角色销毁和重置中的调用:
// ULyraPawnExtensionComponent 中
void ULyraPawnExtensionComponent::UninitializeAbilitySystem()
{
// 清理所有授予的能力集
if (GrantedAbilitySetHandles.AbilitySpecHandles.Num() > 0)
{
GrantedAbilitySetHandles.TakeFromAbilitySystem(GetLyraAbilitySystemComponent());
}
for (auto& Handles : GrantedExtraAbilitySetHandles)
{
Handles.TakeFromAbilitySystem(GetLyraAbilitySystemComponent());
}
}
// 在游戏模式中玩家重生时
void ALyraGameMode::HandlePlayerRespawn(APlayerController* PlayerController)
{
// 重置玩家状态,移除临时能力
if (ALyraPlayerState* PlayerState = PlayerController->GetPlayerState<ALyraPlayerState>())
{
PlayerState->GetAbilitySystemComponent()->RemoveAllGameplayAbilities();
// 然后重新授予基础能力集
PlayerState->GetPawnData()->AbilitySet->GiveToAbilitySystem(...);
}
}
3. 句柄管理方法的实际应用
AddAbilitySpecHandle() 的应用:
// 在技能学习系统中
void ULyraSkillSystem::LearnSkill(USkillDefinition* Skill)
{
if (Skill->AbilitySet)
{
FLyraAbilitySet_GrantedHandles SkillHandles;
Skill->AbilitySet->GiveToAbilitySystem(ASC, &SkillHandles);
// 记录已学习技能的句柄
LearnedSkillHandles.Add(Skill->GetFName(), SkillHandles);
}
}
AddGameplayEffectHandle() 的应用:
// 在Buff系统中
void ULyraBuffSystem::ApplyBuff(UBuffDefinition* Buff)
{
FActiveGameplayEffectHandle EffectHandle = ASC->ApplyGameplayEffect(...);
ActiveBuffHandles.Add(Buff->GetFName(), EffectHandle);
// 或者通过AbilitySet授予
if (Buff->AbilitySet)
{
FLyraAbilitySet_GrantedHandles BuffHandles;
Buff->AbilitySet->GiveToAbilitySystem(ASC, &BuffHandles);
ActiveBuffAbilityHandles.Add(Buff->GetFName(), BuffHandles);
}
}
LyraStarterGame 中的具体配置示例
1. Lyra_Hero_Shooter 能力集配置
// 在编辑器中配置的 AbilitySet 资产
GrantedGameplayAbilities:
- Ability: GA_Weapon_FireProjectile // 发射投射物
AbilityLevel: 1
InputTag: InputTag.Weapon.Fire
- Ability: GA_Weapon_Reload // 装弹
AbilityLevel: 1
InputTag: InputTag.Weapon.Reload
- Ability: GA_Ability_Jump // 跳跃
AbilityLevel: 1
InputTag: InputTag.Ability.Jump
GrantedGameplayEffects:
- GameplayEffect: GE_Shooter_Passive // 射击英雄被动
EffectLevel: 1.0
GrantedAttributes:
- AttributeSet: LyraShooterAttributes // 射击专属属性
2. 武器 AbilitySet 配置
// AssaultRifle_AbilitySet 配置
GrantedGameplayAbilities:
- Ability: GA_AssaultRifle_PrimaryFire
AbilityLevel: 1
InputTag: InputTag.Weapon.Fire
- Ability: GA_AssaultRifle_Reload
AbilityLevel: 1
InputTag: InputTag.Weapon.Reload
GrantedGameplayEffects:
- GameplayEffect: GE_Weapon_AssaultRifle_Damage
EffectLevel: 1.0
3. 游戏模式 AbilitySet 配置
// PvP_GameMode_AbilitySet 配置
GrantedGameplayEffects:
- GameplayEffect: GE_GameMode_RespawnTimer // 重生计时器
EffectLevel: 1.0
- GameplayEffect: GE_GameMode_ScoreTracking // 分数追踪
EffectLevel: 1.0
网络同步和性能优化实践
1. 服务器权威验证
// 在 LyraAbilitySystemComponent 中
bool ULyraAbilitySystemComponent::ShouldGrantAbilities() const
{
// 确保只在服务器端授予能力
return IsOwnerActorAuthoritative();
}
// AbilitySet 的授予始终在服务器执行
void ALyraPlayerState::OnAbilitySystemReady()
{
if (GetLocalRole() == ROLE_Authority && PawnData && PawnData->AbilitySet)
{
PawnData->AbilitySet->GiveToAbilitySystem(GetLyraAbilitySystemComponent(), nullptr, this);
}
}
2. 客户端预测优化
// 对于需要客户端预测的能力,使用 Predicted 标签
FLyraAbilitySet_GameplayAbility:
- Ability: GA_Predicted_Ability
AbilityLevel: 1
InputTag: InputTag.Ability.Predicted
// 在能力定义中设置网络执行策略
UGameplayAbility::SetNetExecutionPolicy(EGameplayAbilityNetExecutionPolicy::LocalPredicted);
这种设计让 LyraStarterGame 能够:
-
模块化管理:不同系统(角色、装备、技能)独立配置能力集
-
数据驱动:在编辑器中配置,无需代码重新编译
-
网络高效:基于GAS的自动同步,减少自定义网络代码
-
易于扩展:添加新能力只需创建新的AbilitySet资产
-
生命周期安全:自动清理,防止内存泄漏和能力残留
LyraAbilitySet 在大型网络游戏中的具体应用分析
LyraAbilitySet.h 中的方法应用
1. FLyraAbilitySet_GrantedHandles::AddAbilitySpecHandle()
应用场景:
-
角色创建时批量记录授予的能力
-
装备系统记录装备赋予的能力
-
技能树系统记录已解锁的技能
网络同步考虑:
// 服务器端记录,客户端通过复制获得能力状态
void OnPlayerSpawn()
{
FLyraAbilitySet_GrantedHandles Handles;
AbilitySet->GiveToAbilitySystem(ASC, &Handles);
// 服务器记录句柄用于后续管理
PlayerAbilityHandles = Handles;
}
2. FLyraAbilitySet_GrantedHandles::AddGameplayEffectHandle()
应用场景:
-
Buff/Debuff系统管理
-
装备附加效果(如+10%攻击力)
-
角色状态效果(如中毒、眩晕)
网络同步考虑:
// GameplayEffect句柄在服务器和客户端间自动同步
void ApplyTeamBuff(APlayerState* Player)
{
FActiveGameplayEffectHandle BuffHandle = ASC->ApplyGameplayEffect(...);
TeamBuffHandles.Add(Player, BuffHandle); // 服务器记录用于后续移除
}
3. FLyraAbilitySet_GrantedHandles::AddAttributeSet()
应用场景:
-
动态添加角色属性(如装备属性)
-
职业特定属性集
-
临时属性修改系统
网络同步考虑:
// 属性集变化会自动同步到客户端
void EquipItem(UItem* Item)
{
UAttributeSet* NewAttrSet = NewObject<UAttributeSet>(...);
ASC->AddAttributeSetSubobject(NewAttrSet);
// 属性值变化通过GAS自动复制到所有客户端
}
4. FLyraAbilitySet_GrantedHandles::TakeFromAbilitySystem()
应用场景:
-
角色死亡时移除所有能力
-
装备卸下时移除装备效果
-
退出游戏时清理资源
-
重置角色状态
网络同步考虑:
void OnPlayerDeath()
{
// 只在服务器执行,变化自动同步到客户端
if (GetLocalRole() == ROLE_Authority)
{
GrantedHandles.TakeFromAbilitySystem(ASC);
// 客户端通过GAS复制看到能力被移除
}
}
5. ULyraAbilitySet::GiveToAbilitySystem()
应用场景:
-
角色职业系统:
void AssignPlayerClass(EPlayerClass Class)
{
ULyraAbilitySet* ClassAbilitySet = GetAbilitySetForClass(Class);
ClassAbilitySet->GiveToAbilitySystem(ASC, &ClassHandles);
// 不同职业获得不同能力组合
}
-
装备系统:
void EquipWeapon(UWeapon* Weapon)
{
Weapon->WeaponAbilitySet->GiveToAbilitySystem(ASC, &WeaponHandles);
// 装备赋予特殊能力和效果
}
-
技能升级系统:
void UnlockSkill(USkill* Skill)
{
Skill->SkillAbilitySet->GiveToAbilitySystem(ASC, &SkillHandles);
// 解锁新技能时授予相关能力
}
大型网络游戏中的具体实现模式
1. 角色创建和初始化
void APlayerCharacter::InitializeAbilities()
{
// 基础角色能力
BaseAbilitySet->GiveToAbilitySystem(ASC, &BaseHandles);
// 职业特定能力
ClassAbilitySet->GiveToAbilitySystem(ASC, &ClassHandles);
// 种族天赋能力
RaceAbilitySet->GiveToAbilitySystem(ASC, &RaceHandles);
// 记录所有句柄用于生命周期管理
AllGrantedHandles.Append(BaseHandles);
AllGrantedHandles.Append(ClassHandles);
AllGrantedHandles.Append(RaceHandles);
}
2. 装备系统实现
class UEquipmentSystem
{
private:
TMap<EEquipmentSlot, FLyraAbilitySet_GrantedHandles> EquipmentHandles;
public:
void EquipItem(EEquipmentSlot Slot, UItem* Item)
{
// 移除旧装备效果
if (EquipmentHandles.Contains(Slot))
{
EquipmentHandles[Slot].TakeFromAbilitySystem(ASC);
}
// 应用新装备效果
if (Item && Item->AbilitySet)
{
Item->AbilitySet->GiveToAbilitySystem(ASC, &EquipmentHandles[Slot]);
}
}
};
3. Buff/Debuff 管理系统
class UBuffSystem
{
private:
TMap<FName, FLyraAbilitySet_GrantedHandles> ActiveBuffs;
public:
void ApplyBuff(FName BuffID, ULyraAbilitySet* BuffAbilitySet)
{
if (ActiveBuffs.Contains(BuffID))
{
// 刷新已存在的Buff
ActiveBuffs[BuffID].TakeFromAbilitySystem(ASC);
}
BuffAbilitySet->GiveToAbilitySystem(ASC, &ActiveBuffs[BuffID]);
// 设置定时移除
GetWorld()->GetTimerManager().SetTimer(
BuffTimers[BuffID],
[this, BuffID]() { RemoveBuff(BuffID); },
BuffDuration, false);
}
void RemoveBuff(FName BuffID)
{
if (ActiveBuffs.Contains(BuffID))
{
ActiveBuffs[BuffID].TakeFromAbilitySystem(ASC);
ActiveBuffs.Remove(BuffID);
}
}
};
4. PvP 竞技场系统
void APvPGameMode::OnRoundStart()
{
// 为所有玩家授予竞技场能力
for (APlayerState* Player : Players)
{
ArenaAbilitySet->GiveToAbilitySystem(Player->GetASC(), &ArenaHandles[Player]);
}
}
void APvPGameMode::OnRoundEnd()
{
// 移除所有竞技场能力
for (auto& HandlePair : ArenaHandles)
{
HandlePair.Value.TakeFromAbilitySystem(HandlePair.Key->GetASC());
}
ArenaHandles.Empty();
}
网络同步和性能优化
1. 权威端控制
void ULyraAbilitySet::GiveToAbilitySystem(ULyraAbilitySystemComponent* LyraASC, ...)
{
if (!LyraASC->IsOwnerActorAuthoritative())
{
return; // 只在服务器执行
}
// 服务器执行后,GAS系统自动同步到客户端
}
2. 批量操作减少网络流量
// 好的做法:使用AbilitySet批量操作
AbilitySet->GiveToAbilitySystem(ASC, &Handles);
// 避免的做法:单独授予每个能力(增加网络流量)
for (auto& Ability : Abilities)
{
ASC->GiveAbility(Ability); // 每次调用都可能产生网络通信
}
3. 生命周期管理
void APlayerCharacter::BeginDestroy()
{
// 清理所有授予的能力,防止内存泄漏
AllGrantedHandles.TakeFromAbilitySystem(ASC);
Super::BeginDestroy();
}
void APlayerCharacter::OnRespawning()
{
// 复活时重新授予持久性能力
PersistentAbilitySet->GiveToAbilitySystem(ASC, &PersistentHandles);
}
实际游戏案例
MMORPG 职业系统
// 战士职业能力集
- GrantedGameplayAbilities: 重击、冲锋、盾牌格挡
- GrantedGameplayEffects: 高生命值、护甲加成
- GrantedAttributes: 力量属性集、耐力属性集
// 法师职业能力集
- GrantedGameplayAbilities: 火球术、寒冰箭、传送
- GrantedGameplayEffects: 法力回复、法术强度
- GrantedAttributes: 智力属性集、精神属性集
竞技游戏装备系统
// 传说武器能力集
- GrantedGameplayAbilities: 特殊攻击、被动效果
- GrantedGameplayEffects: 攻击力提升、移动速度加成
- GrantedAttributes: 武器专属属性集
// 使用方式
void AHeroCharacter::EquipLegendaryWeapon()
{
LegendaryWeaponAbilitySet->GiveToAbilitySystem(ASC, &WeaponHandles);
// 立即获得新能力和属性加成
}
这种设计模式在大型网络游戏中提供了:
-
模块化:不同系统独立管理自己的能力集
-
网络友好:基于GAS的自动同步机制
-
性能优化:批量操作减少网络通信
-
可维护性:统一的生命周期管理
-
扩展性:易于添加新的能力授予系统
848

被折叠的 条评论
为什么被折叠?



