AbilitySystemComponent(ASC)是整个 GAS 系统中的核心。它本质上是一个 UActorComponent(UAbilitySystemComponent),负责处理技能系统中涉及到的所有交互。任意 Actor,只要它想要使用技能 [GameplayAbilities],拥有着属性 Attributes,或者接收效果 GameplayEffects,都必须附着一个 ASC 组件。所有这些对象都存在于、被管理于以及被复制于 ASC(其中 Attributes 是个特例,AttributeSet 负责其复制)。开发者们可以自行根据需要拓展 ASC。
拥有 ASC 的 Actor 也被称为是 ASC 的 OwnerActor。 ASC实际上作用的 Actor 被称为是AvatarActor。OwnerActor 和 AvatarActor 可以是同一个 Actor,比如 MOBA 游戏中的一个简单的 AI 小兵。它们也可以是不同的 Actor,比如 MOBA 游戏中玩家控制的英雄角色,其中 OwnerActor 是 PlayerState 而 AvatarActor 则是 Character 类。大部分的 Actors 都会把 ASC 放在他们自己身上。但是某些情况下比如你的Actor需要使用重生机制,并且在重生后仍然保留死亡之前的 Attributes 或者是 GameplayEffects(例如 MOBA 游戏中的英雄),那么 ASC 的理想位置就是在 PlayerState 上。
注意: 如果你的 ASC 在 PlayerState 上,那么你可能会需要去提高 PlayerState 的网络更新频率(NetUpdateFrequency)。原本 PlayerState 里该值在默认情况下是很低的,可能会导致 Attributes 或者 GameplayTags 在客户端上同步的延迟。如果是这样的话,确保激活 Adaptive Network Update Frequency,这也是Fortnite(堡垒之夜)中的解决办法。
如果 OwnerActor 和 AvatarActor 是不同的 Actor,那么两者都应该去实现接口IAbilitySystemInterface。这个接口只有一个需要重写的方法 UAbilitySystemComponent* GetAbilitySystemComponent() const,会返回一个指针指向它的 ASC 组件。在系统内部,ASC 互相之间就是通过寻找这个接口函数来进行交互。
ASC 存有当前处于激活状态的 GameplayEffects,具体就位于 FActiveGameplayEffectsContainer ActiveGameplayEffects。
ASC 存有它所赋予的 Gameplay Abilities,具体就位于 FGameplayAbilitySpecContainer ActivatableAbilities。无论何时,当你想要遍历ActivatableAbilities.Items,请一定在你的循环之前添加 ABILITYLIST_SCOPE_LOCK(); 语句,以锁定其中的内容以防对其中内容的修改(意外删除某项技能)。ABILITYLIST_SCOPE_LOCK(); 本质上是在作用范围内增加 AbilityScopeLockCount 然后当离开作用范围时相应的减少。不要尝试在 ABILITYLIST_SCOPE_LOCK(); 的作用范围内移除某项技能(清除技能的函数会在内部检查AbilityScopeLockCount,从而防止在内容被锁定的情况下移除技能)。
4.1.1 复制模式 - Replication Mode
ASC 定义了三种不同的复制模式用以复制 GameplayEffects、GameplayTags 以及 GameplayCues,分别是Full、Mixed以及Minimal。Attributes是由他们所在的AttributeSet来进行复制的。
| 复制模式 | 使用情景 | 描述 |
|---|---|---|
Full | 单人 | GameplayEffect 会被复制到所有客户端 |
Mixed | 多人和玩家控制的 Actors | GameplayEffects 仅被复制到拥有者客户端。只有GameplayTags和GameplayCues会被复制到所有客户端 |
Minimal | 多人和AI控制的 Actors | GameplayEffects 不会复制到任何客户端。只有GameplayTags和GameplayCues会被复制到所有客户端 |
注意: Mixed 复制模式要求 OwnerActor 的 Owner 必须是 Controller。PlayerState 的默认 Owner 是 Controller,但是Character 不是。如果使用 Mixed 复制模式时其 OwnerActor 不是 PlayerState,那么你需要调用 OwnerActor 上的 SetOwner() 并传递一个有效的Controller进去。
从4.24版本开始,PossessedBy() 会将 Pawn 的拥有者设置为新的 Controller。
4.1.2 设置和初始化 - Setup and Initialization
ASC 通常是在 OwnerActor 的构造器中进行构造,并且显式得标记为可复制(replicated)。这一步必须在 C++ 内完成。
AGDPlayerState::AGDPlayerState()
{
// Create ability system component, and set it to be explicitly replicated
AbilitySystemComponent = CreateDefaultSubobject<UGDAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
AbilitySystemComponent->SetIsReplicated(true);
//...
}
ASC 需要在服务器和客户端都完成初始化,其中两个重要的初始化参数为 OwnerActor 和 AvatarActor。通常时机是在 Pawn的Controller 设置之后(在 possession 之后)。单人游戏只需要关心服务器路径。
对于玩家控制的角色( ASC 存在于 Pawn 之上),我通常是在 Pawn 的 PossessedBy() 方法中完成 ASC 在服务器的初始化,在 PlayerController 的 AcknowledgePossession() 方法中完成 ASC 在客户端的初始化。
void APACharacterBase::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
if (AbilitySystemComponent)
{
AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
// ASC MixedMode replication requires that the ASC Owner's Owner be the Controller.
SetOwner(NewController);
}
void APAPlayerControllerBase::AcknowledgePossession(APawn* P)
{
Super::AcknowledgePossession(P);
APACharacterBase* CharacterBase = Cast<APACharacterBase>(P);
if (CharacterBase)
{
CharacterBase->GetAbilitySystemComponent()->InitAbilityActorInfo(CharacterBase, CharacterBase);
}
//...
}
对于玩家控制的角色(ASC 存在于 PlayerState 上),我通常是在 Pawn 的 PossessedBy() 方法中完成 ASC 在服务器的初始化,在 Pawn 的 OnRep_PlayerState() 方法中完成 ASC 在客户端的初始化。这确保了 PlayerState 在客户端上已经存在。
// Server only
void AGDHeroCharacter::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC on the Server. Clients do this in OnRep_PlayerState()
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// AI won't have PlayerControllers so we can init again here just to be sure. No harm in initing twice for heroes that have PlayerControllers.
PS->GetAbilitySystemComponent()->InitAbilityActorInfo(PS, this);
}
//...
}
// Client only
void AGDHeroCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC for clients. Server does this in PossessedBy.
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// Init ASC Actor Info for clients. Server will init its ASC when it possesses a new Actor.
AbilitySystemComponent->InitAbilityActorInfo(PS, this);
}
// ...
}
如果你得到如下的错误反馈 LogAbilitySystem: Warning: Can't activate LocalOnly or LocalPredicted ability %s when not local!,那说明你并没有在客户端上初始化你的 ASC。
本文详细介绍了GAS系统中的核心组件AbilitySystemComponent(ASC),包括其在不同Actor之间的应用方式、复制模式的选择以及初始化过程。对于希望深入了解游戏技能系统实现原理的游戏开发者来说,本文提供了宝贵的指导。
2215

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



