GAS学习笔记(一)

最近在用UE5学习GASDocumentation入门GAS,记录一些学习内容,如有错误请指正。

1 初始化AttributeSet

AS可以通过GE和DataTable两种不同方式初始化,Epic推荐使用GE

1.1  通过GamePlayEffect

        GASDocumentation中使用Instant的GameplayEffect,首先创建一个以DefaultAttributes

然后在初始化的时候Apply即可

void AGDCharacterBase::InitializeAttributes()
{
	if (!AbilitySystemComponent.IsValid())
	{
		return;
	}

	if (!DefaultAttributes)
	{
		UE_LOG(LogTemp, Error, TEXT("%s() Missing DefaultAttributes for %s. Please fill in the character's Blueprint."), *FString(__FUNCTION__), *GetName());
		return;
	}

	// Can run on Server and Client
	FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
	EffectContext.AddSourceObject(this);

	FGameplayEffectSpecHandle NewHandle = AbilitySystemComponent->MakeOutgoingSpec(DefaultAttributes, GetCharacterLevel(), EffectContext);
	if (NewHandle.IsValid())
	{
		FActiveGameplayEffectHandle ActiveGEHandle = AbilitySystemComponent->ApplyGameplayEffectSpecToTarget(*NewHandle.Data.Get(), AbilitySystemComponent.Get());
	}
}

1.2  通过DataTable

创建一个DataTable,行结构选择AttributeMetaData,其格式如下。

添加行,将RowName修改为[AttributeSet].[Attribute]并保存该DataTable。

然后找到Character的ASC组件,在Attribute Test条目填上表格即可。 

源码流程分析:

初始化数据表的逻辑就放在ASC的OnRegister函数中,可以看到其直接调用了AttrubiteSet内的InitFromMetaDataTable函数。

void UAbilitySystemComponent::OnRegister()
{
	............

	// Init starting data
	for (int32 i=0; i < DefaultStartingData.Num(); ++i)
	{
		if (DefaultStartingData[i].Attributes && DefaultStartingData[i].DefaultStartingTable)
		{
			UAttributeSet* Attributes = const_cast<UAttributeSet*>(GetOrCreateAttributeSubobject(DefaultStartingData[i].Attributes));
			Attributes->InitFromMetaDataTable(DefaultStartingData[i].DefaultStartingTable);
		}
	}
    ...................
}

先通过 GetOrCreateAttributeSubobject函数获取AttributeSet,其内部其实就是从SpawnedAttributes中获取,如果没有,调用AddSpawnedAttribute函数添加

void UAbilitySystemComponent::AddSpawnedAttribute(UAttributeSet* Attribute)
{
	if (!IsValid(Attribute))
	{
		return;
	}

	if (SpawnedAttributes.Find(Attribute) == INDEX_NONE)
	{
		if (IsUsingRegisteredSubObjectList() && IsReadyForReplication())
		{
			AddReplicatedSubObject(Attribute);
		}

		SpawnedAttributes.Add(Attribute);
		SetSpawnedAttributesListDirty();
	}
}

InitFromMetaDataTable函数的初始化方式也很简单,通过TFieldIterator迭代该AttrubiteSet下的所有属性,然后会分别处理数值类型或FGameplayAttributeData类型。 

void UAttributeSet::InitFromMetaDataTable(const UDataTable* DataTable)
{
    static const FString Context = FString(TEXT("UAttribute::BindToMetaDataTable"));
    for( TFieldIterator<FProperty> It(GetClass(), EFieldIteratorFlags::IncludeSuper) ; It ; ++It )
    {
        FProperty* Property = *It;
        FNumericProperty *NumericProperty = CastField<FNumericProperty>(Property);
        if (NumericProperty)
        {
            // Set Value ...
        }
        else if (FGameplayAttribute::IsGameplayAttributeDataProperty(Property))
        {
            FString RowNameStr = FString::Printf(TEXT("%s.%s"), *Property->GetOwnerVariant().GetName(), *Property->GetName());

            FAttributeMetaData * MetaData = DataTable->FindRow<FAttributeMetaData>(FName(*RowNameStr), Context, false);
            if (MetaData)
            {
                ...
                FGameplayAttributeData* DataPtr = StructProperty->ContainerPtrToValuePtr<FGameplayAttributeData>(this);
                // Set Value ...
                DataPtr->SetBaseValue(MetaData->BaseValue);
				DataPtr->SetCurrentValue(MetaData->BaseValue);
            }
        }
    }
    ...
}

2 技能冷却CooldownGameplayEffect

首先创建一个GameEffect,配置为Has Duration,并且使用TargetTagsGamePlayEffectComponent添加一个Tag

然后在配置在技能Cooldowns即可

在使用技能的时候,会调用CanActivateAbility函数,里面会调用CheckCooldown判断技能CD,其内部就是根据Tag去比对,技能消耗Cost也是类似的实现方案

bool UGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
{
	.....................

	if (!AbilitySystemGlobals.ShouldIgnoreCooldowns() && !CheckCooldown(Handle, ActorInfo, OptionalRelevantTags))
	{
		if (FScopedCanActivateAbilityLogEnabler::IsLoggingEnabled())
		{
			ABILITY_VLOG(ActorInfo->OwnerActor.Get(), Verbose, TEXT("Ability could not be activated due to Cooldown: %s"), *GetName());
		}
		return false;
	}

	if (!AbilitySystemGlobals.ShouldIgnoreCosts() && !CheckCost(Handle, ActorInfo, OptionalRelevantTags))
	{
		if (FScopedCanActivateAbilityLogEnabler::IsLoggingEnabled())
		{
			ABILITY_VLOG(ActorInfo->OwnerActor.Get(), Verbose, TEXT("Ability could not be activated due to Cost: %s"), *GetName());
		}
		return false;
	}

    ......................

	return true;
}

参考资料

【UE】记录GAS中AttributeSet初始化流程 - 知乎

【Unreal】虚幻GAS系统快速入门 - 知乎

虚幻引擎游戏技能系统文档-CSDN博客

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值