UE自学 AbilitySystemComponent没有发现有地方赋值AttributeSet,但是发现可以直接获取到AttributeSet为什么呢?

AbilitySystemComponent没有发现有地方赋值AttributeSet,但是发现可以直接获取到AttributeSet为什么呢?

今天在学习一个gas rpg的视频的时候,有这样的一句代码

const UAuraAttributeSet* AuraAttributeSet = Cast<UAuraAttributeSet>(ASCInterface->GetAbilitySystemComponent()->GetAttributeSet(UAuraAttributeSet::StaticClass()));

我百思不得其解,我没有给AbilitySystemComponent赋值AttributeSet啊,但是为什么可以获取到呢?
学习了下面的文章之后,结合我的代码得到了理解。
我们发现在AAuraCharacter里面的PossessedBy和OnRep_PlayerState里面是这样写的

//服务器初始化ASC
void AAuraCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	//初始化ASC的OwnerActor和AvatarActor
	InitAbilityActorInfo();
}
//客户端初始化ASC
void AAuraCharacter::OnRep_PlayerState()
{
	Super::OnRep_PlayerState();

	//初始化ASC的OwnerActor和AvatarActor
	InitAbilityActorInfo();
}

这两个都调用了InitAbilityActorInfo函数

void AAuraCharacter::InitAbilityActorInfo()
{
	AAuraPlayerState* AuraPlayerState = GetPlayerState<AAuraPlayerState>();
	check(AuraPlayerState);
	/*
	 * InitAbilityActorInfo 是一个重要的方法,用于初始化与能力系统(Ability System)相关的 FGameplayAbilityActorInfo 结构体。
	 * 这个结构体包含了关于执行能力时所需的关键信息,例如谁拥有这个组件、谁控制这个组件以及实际执行动作的 Actor。
	 * InitAbilityActorInfo 的作用InitAbilityActorInfo 方法的主要目的是设置以下关键信息:
	 * •OwnerActor:逻辑上拥有这个组件的 Actor。通常是拥有这个组件的 Actor,例如一个角色或 NPC。
	 * •AvatarActor:实际在世界中执行动作的 Actor。通常是 APawn 或 ACharacter,但也可能是其他类型的 Actor,例如塔、建筑或炮台等。
	 */
	//初始化ASC
	AuraPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(AuraPlayerState, this);
	//从playerState获取ASC
	AbilitySystemComponent = AuraPlayerState->GetAbilitySystemComponent();
	//从playerState获取AS
	AttributeSet = AuraPlayerState->GetAttributeSet();
}

AuraPlayerState作为了我们的OwnerActor。
我们的代码在AuraPlayerState里面定义了UAbilitySystemComponent以及UAttributeSet。
按照下面的文件的理解在GAS使用中,我们会在GAS组件(简称ASC)的OwnerActor(大部分情况下就是Character)中声明并初始化一个AttributeSet。实际上UAbilitySystemComponent在UE的源代码里面执行了InitializeComponent函数,这个InitializeComponent进行了相关的处理。
下面是:UE4 GAS学习小记1:AttributeSet的自动注册 - 知乎 (zhihu.com)的原文,防止原文丢失特意复制过来

在GAS使用中,我们会在GAS组件(简称ASC)的OwnerActor(大部分情况下就是Character)中声明并初始化一个AttributeSet。官方文档中提到,“在OwnerActor的构造函数中创建AttributeSet会自动注册到其ASC”(GitHub - BillEliot/GASDocumentation_Chinese 4.4.1 ),实际使用中也是如此,我们不需要写额外的逻辑就可以通过ASC对AttributeSet进行操作,那么这种自动注册是如何实现的呢?

答案很简单也就是ASC中重写的InitializeComponent()函数啦,但是这里很诡异的是,代码中ASC的实现文件有两个,一个叫AbilitySystemComponent.cpp,一个叫AbilitySystemComponent_Abilities.cpp,而InitializeComponent()是写在后一个文件里的。

(我也不知道为什么要分开两个文件写反正它就是分开了,而且后缀名加了个“Abilities”很容易让人联想到是Ability相关的东西就写在后面这个文件,结果Ability相关的东西确实写在这里,但是其他很多很重要的东西例如Initialize、tick、destroy啥的也写在这里你到底是怎么命名的啊给我老老实实写在AbilitySystemComponent.cpp里面啊)

好以上是吐槽,说回正题,直接贴代码:

void UAbilitySystemComponent::InitializeComponent()
{
   Super::InitializeComponent();

   // Look for DSO AttributeSets (note we are currently requiring all attribute sets to be subobjects of the same owner. This doesn't *have* to be the case forever.
   AActor *Owner = GetOwner();
   InitAbilityActorInfo(Owner, Owner);    // Default init to our outer owner

   // cleanup any bad data that may have gotten into SpawnedAttributes
   TArray<UAttributeSet*>& SpawnedAttributesRef = GetSpawnedAttributes_Mutable();
   for (int32 Idx = SpawnedAttributesRef.Num()-1; Idx >= 0; --Idx)
   {
      if (SpawnedAttributesRef[Idx] == nullptr)
      {
         SpawnedAttributesRef.RemoveAt(Idx);
      }
   }

   TArray<UObject*> ChildObjects;
   GetObjectsWithOuter(Owner, ChildObjects, false, RF_NoFlags, EInternalObjectFlags::PendingKill);

   for (UObject* Obj : ChildObjects)
   {
      UAttributeSet* Set = Cast<UAttributeSet>(Obj);
      if (Set)  
      {
         SpawnedAttributesRef.AddUnique(Set);
         bIsNetDirty = true;
      }
   }
}

可以看到ASC的整个Initialize过程就干了一件事,清除掉旧的AttributeSet,然后添加新的。具体来讲,ASC是通过一个叫做SpawnedAttributes的数组保存所有注册的AttributeSet(要注意一个OwnerActor可以有多个不同的AttributeSet),在InitializeComponent()中,先遍历清空该数组,再通过GetObjectsWithOuter()拿到OwnerActor所有的subobject,遍历,只要是AttributeSet类的,就把它塞到SpawnedAttributes中。

那么InitializeComponent()会在什么时候调用呢,在ActorComponent.h中的官方描述中,总结一句话就是“在组件注册之后,在BeginPlay之前”,所以,当我们在游戏中生成了一个ASC的OwnerActor出来,ASC相关的函数调用顺序会是:构造——注册——InitializeComponent(),然后才是Actor和它的所有组件的BeginPlay。

这样我们一开始游戏就可以直接通过ASC操作AttributeSet啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值