4.1 技能系统组件 - Ability System Component

AbilitySystemComponentASC)是整个 GAS 系统中的核心。它本质上是一个 UActorComponentUAbilitySystemComponent),负责处理技能系统中涉及到的所有交互。任意 Actor,只要它想要使用技能 [GameplayAbilities],拥有着属性 Attributes,或者接收效果 GameplayEffects,都必须附着一个 ASC 组件。所有这些对象都存在于、被管理于以及被复制于 ASC(其中 Attributes 是个特例,AttributeSet 负责其复制)。开发者们可以自行根据需要拓展 ASC

拥有 ASCActor 也被称为是 ASCOwnerActorASC实际上作用的 Actor 被称为是AvatarActorOwnerActorAvatarActor 可以是同一个 Actor,比如 MOBA 游戏中的一个简单的 AI 小兵。它们也可以是不同的 Actor,比如 MOBA 游戏中玩家控制的英雄角色,其中 OwnerActorPlayerStateAvatarActor 则是 Character 类。大部分的 Actors 都会把 ASC 放在他们自己身上。但是某些情况下比如你的Actor需要使用重生机制,并且在重生后仍然保留死亡之前的 Attributes 或者是 GameplayEffects(例如 MOBA 游戏中的英雄),那么 ASC 的理想位置就是在 PlayerState 上。

注意: 如果你的 ASCPlayerState 上,那么你可能会需要去提高 PlayerState 的网络更新频率(NetUpdateFrequency)。原本 PlayerState 里该值在默认情况下是很低的,可能会导致 Attributes 或者 GameplayTags 在客户端上同步的延迟。如果是这样的话,确保激活 Adaptive Network Update Frequency,这也是Fortnite(堡垒之夜)中的解决办法。

如果 OwnerActorAvatarActor 是不同的 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 定义了三种不同的复制模式用以复制 GameplayEffectsGameplayTags 以及 GameplayCues,分别是FullMixed以及MinimalAttributes是由他们所在的AttributeSet来进行复制的。

复制模式使用情景描述
Full单人GameplayEffect 会被复制到所有客户端
Mixed多人和玩家控制的 ActorsGameplayEffects 仅被复制到拥有者客户端。只有GameplayTagsGameplayCues会被复制到所有客户端
Minimal多人和AI控制的 ActorsGameplayEffects 不会复制到任何客户端。只有GameplayTagsGameplayCues会被复制到所有客户端

注意: Mixed 复制模式要求 OwnerActorOwner 必须是 ControllerPlayerState 的默认 OwnerController,但是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 需要在服务器和客户端都完成初始化,其中两个重要的初始化参数为 OwnerActorAvatarActor。通常时机是在 PawnController 设置之后(在 possession 之后)。单人游戏只需要关心服务器路径。

对于玩家控制的角色( ASC 存在于 Pawn 之上),我通常是在 PawnPossessedBy() 方法中完成 ASC 在服务器的初始化,在 PlayerControllerAcknowledgePossession() 方法中完成 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 上),我通常是在 PawnPossessedBy() 方法中完成 ASC 在服务器的初始化,在 PawnOnRep_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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值