ASC学习笔记0024:移除一个现有的属性集
中文注释:UrealEngine-5.2.1源码-AbilitySystemComponent.h
学习内容:
/** 移除一个现有的属性集 */void RemoveSpawnedAttribute(UAttributeSet* Attribute);
这是一个在Gameplay Ability System (GAS) 中常见的函数声明,用于从Ability System Component中移除已添加的属性集。以下是这个函数的典型实现方式:
基本实现
void UYourComponent::RemoveSpawnedAttribute(UAttributeSet* Attribute)
{if (!Attribute || !GetOwnerActor()){return;}// 从已生成的属性集列表中移除SpawnedAttributes.Remove(Attribute);// 如果这个属性集还在主属性集列表中,也从中移除if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(Attribute);}// 可选:销毁属性集对象if (Attribute->IsValidLowLevel()){Attribute->ConditionalBeginDestroy();}
}
更完整的实现示例
void UYourAbilitySystemComponent::RemoveSpawnedAttribute(UAttributeSet* Attribute)
{if (!Attribute){UE_LOG(LogTemp, Warning, TEXT("Attempted to remove null AttributeSet"));return;}if (!SpawnedAttributes.Contains(Attribute)){UE_LOG(LogTemp, Warning, TEXT("AttributeSet not found in SpawnedAttributes"));return;}// 从内部列表中移除SpawnedAttributes.Remove(Attribute);// 从ASC的属性集列表中移除FGameplayAttributeData* AttributeData = nullptr;for (auto It = AttributeSetMap.CreateIterator(); It; ++It){if (It.Value() == Attribute){It.RemoveCurrent();break;}}// 清理并销毁Attribute->PreDestroy();Attribute->ConditionalBeginDestroy();UE_LOG(LogTemp, Log, TEXT("Successfully removed AttributeSet: %s"), *GetNameSafe(Attribute->GetClass()));
}
使用示例
// 假设你有一个对属性集的引用
UAttributeSet* HealthAttributeSet = FindObject<UAttributeSet>(...);// 移除属性集
RemoveSpawnedAttribute(HealthAttributeSet);
HealthAttributeSet = nullptr; // 避免悬空指针
注意事项
-
空指针检查:始终验证输入参数
-
所有权管理:确保正确管理属性集的生命周期
-
组件验证:确认Ability System Component有效
-
列表一致性:保持所有相关列表的同步更新
-
内存管理:适当销毁不再使用的对象
在GAS中的典型使用场景
-
动态添加/移除角色的属性集
-
处理装备系统的属性加成
-
实现临时的状态效果
-
清理不再需要的属性数据
这个函数通常在需要动态管理角色属性时使用,特别是在运行时需要修改属性集配置的情况下。
在实际项目中,RemoveSpawnedAttribute 函数在GAS系统中有着广泛的应用场景。以下是一些具体的实际应用案例:
1. 装备系统 - 动态属性管理
// 装备组件中管理装备带来的属性集
void UEquipmentComponent::UnequipItem(UEquipableItem* Item)
{if (!Item || !Item->GetAttributeSet()){return;}// 移除装备提供的属性集if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(Item->GetAttributeSet());}// 从本地记录中移除EquippedAttributeSets.Remove(Item->GetAttributeSet());// 广播装备移除事件OnItemUnequipped.Broadcast(Item);
}// 装备物品时的对应函数
void UEquipmentComponent::EquipItem(UEquipableItem* Item)
{if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){UAttributeSet* NewAttributeSet = NewObject<UAttributeSet>(this, Item->AttributeSetClass);ASC->AddSpawnedAttribute(NewAttributeSet);EquippedAttributeSets.Add(NewAttributeSet);}
}
2. 状态效果系统 - 临时属性加成
// 状态效果组件管理临时属性
void UStatusEffectComponent::RemoveStatusEffect(FGameplayTag EffectTag)
{if (FStatusEffectData* EffectData = ActiveEffects.Find(EffectTag)){if (EffectData->AttributeSet && EffectData->AttributeSet->IsValidLowLevel()){// 移除状态效果对应的属性集if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(EffectData->AttributeSet);}}ActiveEffects.Remove(EffectTag);OnStatusEffectRemoved.Broadcast(EffectTag);}
}// 添加临时状态效果
void UStatusEffectComponent::ApplyStatusEffect(TSubclassOf<UAttributeSet> EffectAttributeClass, float Duration)
{if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){UAttributeSet* NewEffectAttribute = NewObject<UAttributeSet>(this, EffectAttributeClass);ASC->AddSpawnedAttribute(NewEffectAttribute);FStatusEffectData NewEffect;NewEffect.AttributeSet = NewEffectAttribute;NewEffect.RemainingTime = Duration;ActiveEffects.Add(EffectAttributeClass->GetFName(), NewEffect);}
}
3. 职业/专精系统
// 角色职业管理
void UCharacterClassComponent::SwitchClass(UCharacterClass* NewClass)
{if (CurrentClassAttributeSet){// 移除旧职业的属性集if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(CurrentClassAttributeSet);CurrentClassAttributeSet = nullptr;}}// 添加新职业的属性集if (NewClass && NewClass->ClassAttributeSet){UAttributeSet* NewAttributeSet = NewObject<UAttributeSet>(this, NewClass->ClassAttributeSet);if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->AddSpawnedAttribute(NewAttributeSet);CurrentClassAttributeSet = NewAttributeSet;}}CurrentClass = NewClass;OnClassChanged.Broadcast(NewClass);
}
4. 技能树/天赋系统
// 天赋系统管理选择的属性加成
void UTalentSystemComponent::ResetTalents()
{if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){// 移除所有通过天赋添加的属性集for (UAttributeSet* TalentAttribute : ActiveTalentAttributes){if (TalentAttribute && TalentAttribute->IsValidLowLevel()){ASC->RemoveSpawnedAttribute(TalentAttribute);}}}ActiveTalentAttributes.Empty();SelectedTalents.Empty();// 重新应用基础职业属性ApplyBaseClassAttributes();
}
5. 多人游戏中的同步处理
// 在网络游戏中安全地处理属性集移除
void UPlayerCharacter::Server_RemoveAttributeSet_Implementation(UAttributeSet* AttributeSet)
{if (GetLocalRole() == ROLE_Authority && AttributeSet){// 服务器端移除if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(AttributeSet);}// 通知客户端Multicast_OnAttributeSetRemoved(AttributeSet);}
}// 客户端响应
void UPlayerCharacter::Multicast_OnAttributeSetRemoved_Implementation(UAttributeSet* AttributeSet)
{// 客户端清理本地引用if (GetLocalRole() != ROLE_Authority && AttributeSet){// 避免客户端重复销毁if (OwnedAttributeSets.Contains(AttributeSet)){OwnedAttributeSets.Remove(AttributeSet);}}
}
6. 完整的生命周期管理
// 在角色销毁时清理所有动态属性集
void AAdvancedCharacter::BeginDestroy()
{// 清理所有动态添加的属性集for (UAttributeSet* DynamicAttributeSet : DynamicAttributeSets){if (DynamicAttributeSet && DynamicAttributeSet->IsValidLowLevel()){if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(DynamicAttributeSet);}}}DynamicAttributeSets.Empty();Super::BeginDestroy();
}// 安全的属性集移除函数
void AAdvancedCharacter::SafeRemoveAttributeSet(UAttributeSet* AttributeSet)
{if (!AttributeSet || !IsValid(AttributeSet)){return;}// 检查是否属于这个角色if (!DynamicAttributeSets.Contains(AttributeSet)){UE_LOG(LogGame, Warning, TEXT("Attempting to remove AttributeSet that doesn't belong to this character"));return;}// 从ASC移除if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent()){ASC->RemoveSpawnedAttribute(AttributeSet);}// 从本地记录移除DynamicAttributeSets.Remove(AttributeSet);// 标记为待销毁AttributeSet->MarkAsGarbage();
}
实际项目中的最佳实践
-
引用管理:始终保持对动态属性集的引用,避免内存泄漏
-
网络同步:在多人游戏中确保服务器和客户端状态一致
-
错误处理:添加充分的空指针和有效性检查
-
生命周期:在适当的时机(如角色销毁、关卡切换)清理属性集
-
性能考虑:避免频繁的添加/移除操作,使用属性修饰器(Modifiers)代替
这些实际应用展示了RemoveSpawnedAttribute在构建复杂游戏系统时的重要性,特别是在需要动态修改角色属性的RPG、MMO等游戏类型中。
