ASC学习笔记0022:在不打算修改属性集时访问生成的属性集

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

学习内容:

cpp 复制代码
/** 在不打算修改列表时访问生成的属性列表。 */
	const TArray<UAttributeSet*>& GetSpawnedAttributes() const;

这是一个C++代码片段,来自Unreal Engine项目。让我来解释这个函数声明:

函数说明

功能:获取已生成的属性集列表的只读引用

关键特点

  1. 返回类型const TArray<UAttributeSet*>&

    • 返回对 UAttributeSet 指针数组的常量引用

    • 避免拷贝整个数组,提高性能

    • 防止调用者修改原始数据

  2. const 成员函数

    • 函数末尾的 const 表示该函数不会修改类的成员变量

    • 可以在 const 对象上调用

  3. 使用场景

    • 只需要查看已生成的属性集,而不需要修改它们

    • 用于迭代、查询或显示属性信息

典型用法示例

cpp 复制代码
// 假设在某个类的成员函数中
void SomeFunction() const
{
    // 获取属性列表(只读访问)
    const TArray<UAttributeSet*>& Attributes = GetSpawnedAttributes();
    
    // 可以遍历查看,但不能修改
    for (UAttributeSet* Attr : Attributes)
    {
        if (Attr)
        {
            // 查看属性信息...
            UE_LOG(LogTemp, Warning, TEXT("Attribute Set: %s"), *Attr->GetName());
        }
    }
    
    // 以下代码会编译错误(因为是const引用):
    // Attributes.Add(NewAttribute); // 错误!
    // Attributes.RemoveAt(0);       // 错误!
}

这种设计模式在UE中很常见,既保证了数据的安全性,又提供了高效的访问方式。

在UE项目中,这个函数在Gameplay Ability System (GAS) 架构中有广泛的应用。以下是几个实际应用场景:

1. UI显示属性值

cpp 复制代码
// 在HUD或Widget中显示角色所有属性
void UAttributeWidget::UpdateAttributeDisplay()
{
    if (ACharacter* PlayerCharacter = GetPlayerCharacter())
    {
        if (UAbilitySystemComponent* ASC = PlayerCharacter->FindComponentByClass<UAbilitySystemComponent>())
        {
            const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
            
            for (UAttributeSet* AttributeSet : AttributeSets)
            {
                if (UMyHealthAttributeSet* HealthAttrs = Cast<UMyHealthAttributeSet>(AttributeSet))
                {
                    HealthBar->SetPercent(HealthAttrs->GetHealth() / HealthAttrs->GetMaxHealth());
                }
                else if (UMyStaminaAttributeSet* StaminaAttrs = Cast<UMyStaminaAttributeSet>(AttributeSet))
                {
                    StaminaBar->SetPercent(StaminaAttrs->GetStamina() / StaminaAttrs->GetMaxStamina());
                }
            }
        }
    }
}

2. 属性监听和响应

cpp 复制代码
// 监听所有属性变化
void UAttributeMonitorComponent::InitializeAttributeListeners()
{
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
    {
        const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
        
        for (UAttributeSet* AttributeSet : AttributeSets)
        {
            if (UMyHealthAttributeSet* HealthAttrs = Cast<UMyHealthAttributeSet>(AttributeSet))
            {
                // 监听血量变化
                ASC->GetGameplayAttributeValueChangeDelegate(
                    UMyHealthAttributeSet::GetHealthAttribute()
                ).AddUObject(this, &UAttributeMonitorComponent::OnHealthChanged);
            }
        }
    }
}

3. 存档系统

cpp 复制代码
// 保存所有属性状态
void UGameSaveSystem::SaveAttributes(UGameSave* SaveGame, UAbilitySystemComponent* ASC)
{
    if (!SaveGame || !ASC) return;
    
    const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
    
    for (UAttributeSet* AttributeSet : AttributeSets)
    {
        if (UMyHealthAttributeSet* HealthAttrs = Cast<UMyHealthAttributeSet>(AttributeSet))
        {
            SaveGame->SavedHealth = HealthAttrs->GetHealth();
            SaveGame->SavedMaxHealth = HealthAttrs->GetMaxHealth();
        }
        else if (UMyManaAttributeSet* ManaAttrs = Cast<UMyManaAttributeSet>(AttributeSet))
        {
            SaveGame->SavedMana = ManaAttrs->GetMana();
            SaveGame->SavedMaxMana = ManaAttrs->GetMaxMana();
        }
    }
}

4. Debug和开发工具

cpp 复制代码
// 在控制台显示所有属性值
void AMyPlayerController::DebugShowAttributes()
{
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
    {
        const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
        
        UE_LOG(LogTemp, Warning, TEXT("=== Current Attributes ==="));
        
        for (UAttributeSet* AttributeSet : AttributeSets)
        {
            FString AttributeSetName = AttributeSet->GetClass()->GetName();
            UE_LOG(LogTemp, Warning, TEXT("Attribute Set: %s"), *AttributeSetName);
            
            // 使用反射获取所有属性值
            for (TFieldIterator<FProperty> PropIt(AttributeSet->GetClass()); PropIt; ++PropIt)
            {
                FProperty* Property = *PropIt;
                if (Property->IsA<FGameplayAttribute>())
                {
                    // 显示属性名称和值...
                }
            }
        }
    }
}

5. 条件检查和验证

cpp 复制代码
// 检查是否满足技能施放条件
bool UMyGameplayAbility::CheckAttributeRequirements()
{
    if (UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo())
    {
        const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
        
        for (UAttributeSet* AttributeSet : AttributeSets)
        {
            if (UMyResourceAttributeSet* ResourceAttrs = Cast<UMyResourceAttributeSet>(AttributeSet))
            {
                // 检查法力值是否足够
                if (ResourceAttrs->GetMana() < RequiredManaCost)
                {
                    return false;
                }
                
                // 检查血量是否高于最低要求
                if (ResourceAttrs->GetHealth() < MinimumHealthThreshold)
                {
                    return false;
                }
            }
        }
    }
    
    return true;
}

6. AI决策系统

cpp 复制代码
// AI根据属性状态做出决策
ECombatBehavior UMyAIController::EvaluateCombatBehavior()
{
    if (UAbilitySystemComponent* ASC = GetPawn()->FindComponentByClass<UAbilitySystemComponent>())
    {
        const TArray<UAttributeSet*>& AttributeSets = ASC->GetSpawnedAttributes();
        
        for (UAttributeSet* AttributeSet : AttributeSets)
        {
            if (UMyHealthAttributeSet* HealthAttrs = Cast<UMyHealthAttributeSet>(AttributeSet))
            {
                float HealthPercent = HealthAttrs->GetHealth() / HealthAttrs->GetMaxHealth();
                
                if (HealthPercent < 0.3f) return ECombatBehavior::Retreat;
                if (HealthPercent < 0.6f) return ECombatBehavior::Defensive;
            }
        }
    }
    
    return ECombatBehavior::Aggressive;
}

关键优势

  1. 性能高效 - 返回引用避免数组拷贝

  2. 数据安全 - const引用防止意外修改

  3. 接口清晰 - 明确表示这是只读操作

  4. GAS集成 - 完美配合UE的Gameplay Ability System

这种设计模式在需要查看但不修改属性集的场景中非常实用,特别是在UI、存档、调试和AI系统中。

相关推荐
初夏睡觉2 小时前
P1048 [NOIP 2005 普及组] 采药
数据结构·c++·算法
上去我就QWER2 小时前
C++中的堆和栈
开发语言·c++
小欣加油2 小时前
leetcode 1513 仅含1的子串数
c++·算法·leetcode·职场和发展
HalvmånEver2 小时前
Linux:基础开发工具(四)
linux·运维·服务器·开发语言·学习·makefile
专注VB编程开发20年2 小时前
.net按地址动态调用VC++DLL将非托管DLL中的函数地址转换为.NET可调用的委托
开发语言·c++·c#·.net
q***78782 小时前
Spring学习——新建module模块
java·学习·spring
01100001乄夵2 小时前
第六课:仿真进阶与调试技巧
经验分享·笔记·学习方法
kanimito3 小时前
大语言模型入门指南:从科普到实战的技术笔记(2)
人工智能·笔记·语言模型
Bin二叉3 小时前
南京大学cpp复习——面向对象第一部分(构造函数,拷贝构造函数,析构函数,移动构造函数,友元)
c++·笔记·学习