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){// 法力属性集存在}
}
注意事项
-
BlueprintPure = false: 表示这个函数可能有副作用,不适合在蓝图中作为纯函数使用
-
const 返回值: 返回的是const指针,防止修改属性集
-
类型安全: 使用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()){// 获取各种属性集来更新UIif (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>()){// 应用体力消耗的GameplayEffectFGameplayEffectSpecHandle 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();}
}
最佳实践建议
-
空指针检查:始终检查返回值是否为nullptr
-
缓存引用:对于频繁访问的属性集,考虑缓存引用
-
属性变化监听:使用属性变化委托而不是每帧查询
-
线程安全:确保在正确的时机访问属性集
这些实际应用展示了GetAttributeSet在游戏开发中的核心作用,是构建复杂属性系统的基石。
