ASC学习笔记0018:返回属性集实例的引用(如果此组件中存在)

中文注释:UrealEngine-5.2.1源码-AbilitySystemComponent.h

学习内容:

/**
	 * 返回属性集实例的引用(如果此组件中存在)
	 *
	 * @param AttributeSetClass 要查找的属性集类型
	 * @param bFound 如果属性集实例存在则设置为true
	 */
	UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Attributes")
	const UAttributeSet* GetAttributeSet(TSubclassOf<UAttributeSet> AttributeSetClass) const;

这是一个典型的Unreal Engine游戏属性系统相关的函数声明。让我为您详细解释这个函数:

函数功能

此函数用于从游戏组件中查找并返回指定类型的属性集实例。

参数说明

  • AttributeSetClass: 要查找的属性集类型(使用TSubclassOf模板确保类型安全)

  • 返回值: 找到的属性集实例的const指针,如果未找到则返回nullptr

使用示例

// 假设有这些属性集类
UCLASS()
class UHealthAttributeSet : public UAttributeSet { /*...*/ };

UCLASS()
class UManaAttributeSet : public UAttributeSet { /*...*/ };

// 使用示例
void ExampleUsage()
{
    // 获取组件引用(假设在某个Actor中)
    UActorComponent* Component = ...;
    
    // 查找健康属性集
    if (const UHealthAttributeSet* HealthSet = Component->GetAttributeSet(UHealthAttributeSet::StaticClass()))
    {
        // 成功找到健康属性集,可以使用它
        float CurrentHealth = HealthSet->GetHealth();
    }
    
    // 或者检查是否存在某个属性集
    const UAttributeSet* FoundSet = Component->GetAttributeSet(UManaAttributeSet::StaticClass());
    if (FoundSet)
    {
        // 法力属性集存在
    }
}
 

注意事项

  1. BlueprintPure = false: 表示这个函数可能有副作用,不适合在蓝图中作为纯函数使用

  2. const 返回值: 返回的是const指针,防止修改属性集

  3. 类型安全: 使用TSubclassOf确保传入的是有效的UAttributeSet子类

典型应用场景

  • 在技能系统中访问角色的各种属性

  • 在UI中显示角色属性值

  • 在游戏逻辑中检查属性状态

  • 实现属性修改和效果应用

这个函数是UE游戏能力系统(GAS)中的核心组件之一,用于管理角色的各种数值属性。

在实际项目中,GetAttributeSet 函数在游戏能力系统(GAS)中有着广泛的应用。以下是一些真实的使用场景:

1. 技能效果执行时获取属性

// 在GameplayEffectExecutionCalculation中
void UDamageExecution::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
    // 获取目标角色的属性集
    const UHealthAttributeSet* HealthSet = ExecutionParams.GetTargetAbilitySystemComponent()->GetAttributeSet<UHealthAttributeSet>();
    const UCombatAttributeSet* CombatSet = ExecutionParams.GetTargetAbilitySystemComponent()->GetAttributeSet<UCombatAttributeSet>();
    
    if (HealthSet && CombatSet)
    {
        // 计算伤害,考虑护甲等属性
        float BaseDamage = 50.0f;
        float ArmorReduction = CombatSet->GetArmor() * 0.1f;
        float FinalDamage = FMath::Max(0, BaseDamage - ArmorReduction);
        
        // 应用伤害到健康值
        OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(
            UHealthAttributeSet::GetHealthAttribute(), 
            EGameplayModOp::Additive, 
            -FinalDamage
        ));
    }
}
 

2. UI 系统更新显示

// 在角色HUD Widget中
void UPlayerHUDWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
    Super::NativeTick(MyGeometry, InDeltaTime);
    
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
    {
        // 获取各种属性集来更新UI
        if (const UHealthAttributeSet* HealthSet = ASC->GetAttributeSet<UHealthAttributeSet>())
        {
            HealthBar->SetPercent(HealthSet->GetHealth() / HealthSet->GetMaxHealth());
            HealthText->SetText(FText::AsNumber(HealthSet->GetHealth()));
        }
        
        if (const UManaAttributeSet* ManaSet = ASC->GetAttributeSet<UManaAttributeSet>())
        {
            ManaBar->SetPercent(ManaSet->GetMana() / ManaSet->GetMaxMana());
        }
        
        if (const UStaminaAttributeSet* StaminaSet = ASC->GetAttributeSet<UStaminaAttributeSet>())
        {
            StaminaBar->SetPercent(StaminaSet->GetStamina() / StaminaSet->GetMaxStamina());
        }
    }
}
 

3. 条件检查和游戏逻辑

// 在自定义游戏能力中
bool UDashAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const
{
    if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
    {
        return false;
    }
    
    // 检查是否有足够的体力来施展冲刺
    if (const UStaminaAttributeSet* StaminaSet = GetAbilitySystemComponentFromActorInfo()->GetAttributeSet<UStaminaAttributeSet>())
    {
        return StaminaSet->GetStamina() >= RequiredStaminaCost;
    }
    
    return false;
}

void UDashAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
    // 消耗体力
    if (UStaminaAttributeSet* StaminaSet = GetAbilitySystemComponentFromActorInfo()->GetAttributeSet<UStaminaAttributeSet>())
    {
        // 应用体力消耗的GameplayEffect
        FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(StaminaCostEffect);
        ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, SpecHandle);
    }
    
    // 执行冲刺逻辑...
}
 

4. AI 行为树决策

// AI服务节点中检查属性状态
UBTService_CheckHealth::UBTService_CheckHealth()
{
    NodeName = "Check Health Status";
}

void UBTService_CheckHealth::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
    Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
    
    AAIController* AIController = OwnerComp.GetAIOwner();
    if (AIController && AIController->GetPawn())
    {
        if (UAbilitySystemComponent* ASC = AIController->GetPawn()->FindComponentByClass<UAbilitySystemComponent>())
        {
            if (const UHealthAttributeSet* HealthSet = ASC->GetAttributeSet<UHealthAttributeSet>())
            {
                float HealthPercent = HealthSet->GetHealth() / HealthSet->GetMaxHealth();
                
                // 根据血量设置行为树变量
                OwnerComp.GetBlackboardComponent()->SetValueAsBool(IsLowHealthKey.SelectedKeyName, HealthPercent < 0.3f);
                OwnerComp.GetBlackboardComponent()->SetValueAsBool(IsCriticalHealthKey.SelectedKeyName, HealthPercent < 0.1f);
            }
        }
    }
}
 

5. 物品和装备系统

// 装备物品时修改属性
void UEquippableItem::OnEquipped(AActor* Owner)
{
    if (UAbilitySystemComponent* ASC = Owner->FindComponentByClass<UAbilitySystemComponent>())
    {
        // 检查角色是否有对应的属性集
        if (const UCombatAttributeSet* CombatSet = ASC->GetAttributeSet<UCombatAttributeSet>())
        {
            // 应用装备加成
            FGameplayEffectContextHandle EffectContext = ASC->MakeEffectContext();
            EffectContext.AddSourceObject(this);
            
            FGameplayEffectSpecHandle SpecHandle = ASC->MakeOutgoingSpec(EquipmentEffect, 1, EffectContext);
            if (SpecHandle.IsValid())
            {
                ASC->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get());
            }
        }
    }
}
 

6. 保存/加载系统

// 保存角色属性状态
void UPlayerSaveGame::SaveAttributes(UAbilitySystemComponent* ASC)
{
    if (!ASC) return;
    
    // 保存健康属性
    if (const UHealthAttributeSet* HealthSet = ASC->GetAttributeSet<UHealthAttributeSet>())
    {
        SavedHealth = HealthSet->GetHealth();
        SavedMaxHealth = HealthSet->GetMaxHealth();
    }
    
    // 保存法力属性
    if (const UManaAttributeSet* ManaSet = ASC->GetAttributeSet<UManaAttributeSet>())
    {
        SavedMana = ManaSet->GetMana();
        SavedMaxMana = ManaSet->GetMaxMana();
    }
    
    // 保存经验值
    if (const UExperienceAttributeSet* ExpSet = ASC->GetAttributeSet<UExperienceAttributeSet>())
    {
        SavedExperience = ExpSet->GetExperience();
        SavedLevel = ExpSet->GetLevel();
    }
}
 

最佳实践建议

  1. 空指针检查:始终检查返回值是否为nullptr

  2. 缓存引用:对于频繁访问的属性集,考虑缓存引用

  3. 属性变化监听:使用属性变化委托而不是每帧查询

  4. 线程安全:确保在正确的时机访问属性集

这些实际应用展示了GetAttributeSet在游戏开发中的核心作用,是构建复杂属性系统的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值