ASC学习笔记0014:手动添加一个新的属性集

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

学习内容:

cpp 复制代码
/** 
	 * 手动添加一个新的属性集,作为此能力系统组件的子对象。
	 * 此组件的所有子对象在初始化期间会自动添加。
	 */
	template <class T>
	const T* AddAttributeSetSubobject(T* Subobject)
	{
		AddSpawnedAttribute(Subobject);
		return Subobject;
	}

这是一个用于游戏能力系统组件(Ability System Component)中动态添加属性集(Attribute Set)子对象的方法。让我为您详细解释这个函数:

函数分析

功能说明

  • 目的:手动向能力系统组件添加一个属性集子对象

  • 使用场景:当需要动态添加属性集,而不是在初始化期间自动添加时

  • 返回值:返回添加的属性集指针(const限定)

关键组件

  1. 模板函数:支持任何继承自属性集基类的类型

  2. AddSpawnedAttribute:内部方法,实际执行添加操作

  3. 返回const指针:防止外部意外修改

使用示例

cpp 复制代码
// 假设有一个自定义属性集类
class UMyCustomAttributeSet : public UAttributeSet
{
    // 属性定义...
};

// 在能力系统组件中使用
UMyCustomAttributeSet* NewAttributeSet = NewObject<UMyCustomAttributeSet>(this);
const UMyCustomAttributeSet* AddedSet = AddAttributeSetSubobject(NewAttributeSet);

设计考虑

  1. 灵活性:允许运行时动态添加属性集

  2. 类型安全:模板确保类型正确性

  3. 所有权明确:组件管理属性集的生命周期

  4. 接口一致性:与自动添加的属性集使用相同的基础设施

这种设计在需要条件性添加属性集或支持插件式架构时特别有用。

在实际项目中,AddAttributeSetSubobject 方法在Gameplay Ability System (GAS) 中有广泛的应用。以下是一些典型的使用场景和实际案例:

1. 角色能力组件初始化

基础角色类

cpp 复制代码
// MyCharacter.h
UCLASS()
class AMyCharacter : public ACharacter, public IAbilitySystemInterface
{
    GENERATED_BODY()

public:
    AMyCharacter();

    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystemComponent; }

protected:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Abilities")
    TObjectPtr<UMyAbilitySystemComponent> AbilitySystemComponent;

    UPROPERTY()
    TObjectPtr<UHealthAttributeSet> HealthAttributes;
    
    UPROPERTY()
    TObjectPtr<UManaAttributeSet> ManaAttributes;
    
    UPROPERTY()
    TObjectPtr<UCombatAttributeSet> CombatAttributes;
};

// MyCharacter.cpp
AMyCharacter::AMyCharacter()
{
    // 创建能力系统组件
    AbilitySystemComponent = CreateDefaultSubobject<UMyAbilitySystemComponent>("AbilitySystemComponent");
    
    // 创建并添加属性集
    HealthAttributes = CreateDefaultSubobject<UHealthAttributeSet>("HealthAttributes");
    ManaAttributes = CreateDefaultSubobject<UManaAttributeSet>("ManaAttributes");
    CombatAttributes = CreateDefaultSubobject<UCombatAttributeSet>("CombatAttributes");
    
    // 设置组件依附关系
    AbilitySystemComponent->SetupAttachment(RootComponent);
}
复制代码

自定义能力系统组件

cpp 复制代码
// MyAbilitySystemComponent.h
UCLASS()
class UMyAbilitySystemComponent : public UAbilitySystemComponent
{
    GENERATED_BODY()

public:
    template <class T>
    const T* AddAttributeSetSubobject(T* Subobject)
    {
        AddSpawnedAttribute(Subobject);
        return Subobject;
    }

protected:
    virtual void AddSpawnedAttribute(UAttributeSet* AttributeSet);
};

// MyAbilitySystemComponent.cpp
void UMyAbilitySystemComponent::AddSpawnedAttribute(UAttributeSet* AttributeSet)
{
    if (AttributeSet)
    {
        SpawnedAttributes.Add(AttributeSet);
        AddAttributeSetSubobject(AttributeSet);
        
        // 触发属性集初始化事件
        OnAttributeSetAdded.Broadcast(AttributeSet);
    }
}
复制代码

2. 复杂的职业系统

不同职业的属性配置

cpp 复制代码
// WarriorCharacter.cpp
AWarriorCharacter::AWarriorCharacter()
{
    AbilitySystemComponent = CreateDefaultSubobject<UMyAbilitySystemComponent>("AbilitySystemComponent");
    
    // 战士特有属性集
    HealthAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UHealthAttributeSet>("HealthAttributes"));
    StaminaAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UStaminaAttributeSet>("StaminaAttributes"));
    StrengthAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UStrengthAttributeSet>("StrengthAttributes"));
    DefenseAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UDefenseAttributeSet>("DefenseAttributes"));
}

// MageCharacter.cpp
AMageCharacter::AMageCharacter()
{
    AbilitySystemComponent = CreateDefaultSubobject<UMyAbilitySystemComponent>("AbilitySystemComponent");
    
    // 法师特有属性集
    HealthAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UHealthAttributeSet>("HealthAttributes"));
    ManaAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UManaAttributeSet>("ManaAttributes"));
    IntelligenceAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<UIntelligenceAttributeSet>("IntelligenceAttributes"));
    SpellPowerAttributes = AbilitySystemComponent->AddAttributeSetSubobject(CreateDefaultSubobject<USpellPowerAttributeSet>("SpellPowerAttributes"));
}
复制代码

3. 动态属性集管理

运行时添加/移除属性集

cpp 复制代码
// 动态添加临时属性集(如增益效果)
void UMyAbilitySystemComponent::AddTemporaryAttributeSet(UAttributeSet* TempAttributeSet)
{
    if (TempAttributeSet && !TemporaryAttributeSets.Contains(TempAttributeSet))
    {
        AddAttributeSetSubobject(TempAttributeSet);
        TemporaryAttributeSets.Add(TempAttributeSet);
        
        // 通知属性变化
        ForceReplication();
    }
}

void UMyAbilitySystemComponent::RemoveTemporaryAttributeSet(UAttributeSet* TempAttributeSet)
{
    if (TemporaryAttributeSets.Remove(TempAttributeSet))
    {
        RemoveSpawnedAttribute(TempAttributeSet);
    }
}
复制代码

4. 装备系统集成

装备提供的属性集

cpp 复制代码
// EquipmentComponent.cpp
void UEquipmentComponent::OnEquipmentEquipped(UEquipmentItem* Equipment)
{
    if (Equipment && Equipment->GrantedAttributeSet)
    {
        // 为装备创建属性集实例
        UAttributeSet* EquipmentAttributeSet = NewObject<UAttributeSet>(GetOwner(), Equipment->GrantedAttributeSet);
        
        // 添加到能力系统组件
        if (UAbilitySystemComponent* ASC = GetOwnerAbilitySystemComponent())
        {
            if (UMyAbilitySystemComponent* MyASC = Cast<UMyAbilitySystemComponent>(ASC))
            {
                MyASC->AddAttributeSetSubobject(EquipmentAttributeSet);
                EquippedAttributeSets.Add(EquipmentAttributeSet);
            }
        }
    }
}
复制代码

5. 状态效果系统

状态效果属性集

cpp 复制代码
// StatusEffectComponent.cpp
void UStatusEffectComponent::ApplyStatusEffect(FStatusEffectHandle EffectHandle)
{
    if (UStatusEffect* StatusEffect = EffectHandle.GetEffect())
    {
        // 创建状态效果属性集
        UStatusEffectAttributeSet* EffectAttributeSet = NewObject<UStatusEffectAttributeSet>(this);
        EffectAttributeSet->InitializeFromEffect(StatusEffect);
        
        // 添加到能力系统
        if (UMyAbilitySystemComponent* MyASC = GetMyAbilitySystemComponent())
        {
            MyASC->AddAttributeSetSubobject(EffectAttributeSet);
            ActiveEffectAttributeSets.Add(EffectHandle, EffectAttributeSet);
        }
    }
}
复制代码

6. 网络同步优化

属性复制配置

cpp 复制代码
// 在属性集中配置网络同步
UCLASS()
class UHealthAttributeSet : public UAttributeSet
{
    GENERATED_BODY()

public:
    UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health)
    FGameplayAttributeData Health;
    
    UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_MaxHealth)
    FGameplayAttributeData MaxHealth;

    // 复制通知
    UFUNCTION()
    void OnRep_Health(const FGameplayAttributeData& OldHealth);
    
    UFUNCTION()
    void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
    
    // 网络复制
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
复制代码

实际项目中的最佳实践

  1. 明确的命名约定:属性集名称要清晰表达其用途

  2. 模块化设计:每个属性集专注于单一职责

  3. 内存管理:及时清理不再使用的属性集

  4. 网络优化:合理配置复制属性,减少带宽占用

  5. 错误处理:添加适当的空指针检查和验证

这种模式在大型项目中特别有用,因为它提供了清晰的架构来管理复杂的游戏属性系统,同时保持了代码的可维护性和扩展性。

相关推荐
水天需01014 分钟前
VS Code C++ 环境配置及 HelloWorld 程序
c++
初圣魔门首席弟子14 分钟前
第六章、[特殊字符] HTTP 深度进阶:报文格式 + 服务器实现(从理论到代码)
linux·网络·c++
永远都不秃头的程序员(互关)18 分钟前
查找算法深入分析与实践:从线性查找到二分查找
数据结构·c++·算法
Sunsets_Red19 分钟前
二项式定理
java·c++·python·算法·数学建模·c#
菜鸟‍19 分钟前
【论文学习】SAMed-2: 选择性记忆增强的医学任意分割模型
人工智能·学习·算法
weixin_4093831221 分钟前
简单四方向a*寻路学习记录2 先做个数组地图 在cocos编辑器模式上运行出格子 计算角色世界坐标跟数组地图的联系
学习·编辑器·cocos
一过菜只因24 分钟前
MySql学习(2)
数据库·学习·mysql
好评12430 分钟前
C/C++ 内存管理:摆脱野指针和内存泄漏
开发语言·c++·内存管理·c/c++
灰灰勇闯IT35 分钟前
虚拟机性能优化实战:从基础调优到深度压榨性能
开发语言·学习·性能优化·虚拟机
xxp432136 分钟前
Linux 根文件系统构建
linux·学习