ASC学习笔记0025:移除所有属性集

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

学习内容:

cpp 复制代码
/** 移除所有属性集 */
	void RemoveAllSpawnedAttributes();

这是一个在游戏开发(尤其是Unreal Engine)中常见的函数声明。让我来解释它的作用、典型实现方式和使用场景。

函数作用

RemoveAllSpawnedAttributes() 函数用于移除所有通过"生成"(Spawn)方式添加的属性(Attributes),通常用于:

  • 清理资源:在对象销毁或重置时释放属性占用的内存

  • 状态重置:将对象恢复到初始状态

  • 防止内存泄漏:确保动态创建的属性被正确清理

典型实现示例

Unreal Engine C++ 实现

cpp 复制代码
// 在属性管理类中
void UAttributeSet::RemoveAllSpawnedAttributes()
{
    // 遍历并移除所有生成的属性
    for (auto& Attribute : SpawnedAttributes)
    {
        if (Attribute && Attribute->IsValidLowLevel())
        {
            Attribute->ConditionalBeginDestroy();
        }
    }
    SpawnedAttributes.Empty();
}

// 在Actor或Component中
void UMyAbilitySystemComponent::RemoveAllSpawnedAttributes()
{
    if (SpawnedAttributes.Num() > 0)
    {
        for (UAttributeSet* AttributeSet : SpawnedAttributes)
        {
            AttributeSet->RemoveAllSpawnedAttributes();
        }
        SpawnedAttributes.Empty();
    }
}

通用 C++ 实现

cpp 复制代码
class GameCharacter {
private:
    std::vector<std::unique_ptr<Attribute>> spawnedAttributes;
    
public:
    void RemoveAllSpawnedAttributes() {
        // 清空vector,unique_ptr会自动删除对象
        spawnedAttributes.clear();
    }
    
    // 添加属性的方法
    void AddSpawnedAttribute(std::unique_ptr<Attribute> attribute) {
        spawnedAttributes.push_back(std::move(attribute));
    }
};

使用场景

1. 角色死亡或重置时

cpp 复制代码
void AMyCharacter::OnDeath()
{
    // 移除所有战斗中生成的临时属性
    RemoveAllSpawnedAttributes();
    // 其他清理逻辑...
}

2. 场景切换时

cpp 复制代码
void AMyGameMode::OnMapChange()
{
    // 清理所有玩家的生成属性
    for (APlayerController* Player : Players)
    {
        if (AMyCharacter* Character = Cast<AMyCharacter>(Player->GetPawn()))
        {
            Character->RemoveAllSpawnedAttributes();
        }
    }
}

3. 技能系统清理

cpp 复制代码
void UMyAbility::EndAbility()
{
    // 移除该技能生成的所有属性效果
    RemoveAllSpawnedAttributes();
    Super::EndAbility();
}

最佳实践

  1. 在析构函数中调用
cpp 复制代码
UMyComponent::~UMyComponent()
{
    RemoveAllSpawnedAttributes();
}
  1. 添加安全检查
cpp 复制代码
void RemoveAllSpawnedAttributes()
{
    if (SpawnedAttributes.Num() == 0) return;
    
    // 倒序遍历避免移除时的索引问题
    for (int32 i = SpawnedAttributes.Num() - 1; i >= 0; --i)
    {
        if (SpawnedAttributes[i])
        {
            SpawnedAttributes[i]->PreRemove();
            SpawnedAttributes[i]->ConditionalBeginDestroy();
        }
    }
    SpawnedAttributes.Empty();
}

这个函数是游戏对象生命周期管理中的重要组成部分,确保资源被正确清理,避免内存泄漏和状态混乱。

在实际游戏项目中,RemoveAllSpawnedAttributes() 有着广泛而重要的应用。让我通过几个真实案例来说明:

1. 技能系统(Ability System)

临时属性效果管理

cpp 复制代码
// 在技能激活时添加属性,结束时清理
void UPoisonDamageAbility::OnAbilityActivate()
{
    // 添加中毒效果相关的属性
    UAttributeSet* PoisonAttribute = SpawnAttribute(UPoisonAttributeSet::StaticClass());
    PoisonAttribute->SetDamagePerSecond(10.0f);
    PoisonAttribute->SetDuration(5.0f);
}

void UPoisonDamageAbility::OnAbilityEnd()
{
    // 清理中毒效果的所有属性
    RemoveAllSpawnedAttributes();
}

// 在技能组件中
void UAbilitySystemComponent::RemoveAllAbilities()
{
    // 移除所有技能及其生成的属性
    for (auto& Ability : ActiveAbilities)
    {
        Ability->RemoveAllSpawnedAttributes();
    }
    ActiveAbilities.Empty();
}

2. 装备/道具系统

装备属性管理

cpp 复制代码
// 装备组件
void UEquipmentComponent::UnequipAll()
{
    // 移除所有装备提供的属性加成
    RemoveAllSpawnedAttributes();
    
    // 清空装备列表
    EquippedItems.Empty();
}

void UEquipmentComponent::OnItemEquipped(UEquippableItem* Item)
{
    if (Item && Item->AttributeSetClass)
    {
        // 生成装备属性集
        UAttributeSet* EquipmentAttributes = SpawnAttribute(Item->AttributeSetClass);
        EquipmentAttributes->InitializeFromItem(Item);
    }
}

// 切换装备时
void UEquipmentComponent::SwapEquipment(UEquippableItem* NewItem)
{
    // 先移除当前装备的所有属性
    RemoveAllSpawnedAttributes();
    
    // 再添加新装备属性
    if (NewItem)
    {
        OnItemEquipped(NewItem);
    }
}

3. BUFF/DEBUFF 系统

状态效果管理

cpp 复制代码
// BUFF管理器
void UBuffManager::ApplyBuff(FBuffData BuffData)
{
    UAttributeSet* BuffAttributes = SpawnAttribute(UBuffAttributeSet::StaticClass());
    BuffAttributes->SetModifiers(BuffData.Modifiers);
    BuffAttributes->SetExpireTime(GetWorld()->GetTimeSeconds() + BuffData.Duration);
    
    ActiveBuffs.Add(BuffAttributes);
}

void UBuffManager::ClearExpiredBuffs()
{
    float CurrentTime = GetWorld()->GetTimeSeconds();
    
    for (int32 i = ActiveBuffs.Num() - 1; i >= 0; --i)
    {
        if (ActiveBuffs[i]->GetExpireTime() <= CurrentTime)
        {
            ActiveBuffs[i]->ConditionalBeginDestroy();
            ActiveBuffs.RemoveAt(i);
        }
    }
}

void UBuffManager::ClearAllBuffs()
{
    RemoveAllSpawnedAttributes();
    ActiveBuffs.Empty();
}

// 在角色中应用
void AMyCharacter::OnEnterSafeZone()
{
    // 进入安全区移除所有负面效果
    BuffManager->ClearAllBuffs();
    DebuffManager->RemoveAllSpawnedAttributes();
}

4. 多人游戏同步

网络同步清理

cpp 复制代码
// 在网络角色中
void AMyNetworkCharacter::OnRespawning()
{
    if (GetLocalRole() == ROLE_Authority)
    {
        // 服务器端清理属性
        RemoveAllSpawnedAttributes();
        
        // 通知客户端同步清理
        Client_RemoveAllSpawnedAttributes();
    }
}

// 客户端RPC
void AMyNetworkCharacter::Client_RemoveAllSpawnedAttributes_Implementation()
{
    RemoveAllSpawnedAttributes();
}

// 连接断开处理
void AMyGameSession::HandlePlayerDisconnect(APlayerController* Player)
{
    if (AMyNetworkCharacter* Character = Cast<AMyNetworkCharacter>(Player->GetPawn()))
    {
        Character->RemoveAllSpawnedAttributes();
    }
}

5. 场景/关卡管理

关卡切换资源清理

cpp 复制代码
// 游戏模式中
void AMyGameMode::OnPreLoadMap(const FString& MapName)
{
    // 清理所有玩家的生成属性
    for (APlayerState* PlayerState : GameState->PlayerArray)
    {
        if (AMyPlayerState* MyPlayerState = Cast<AMyPlayerState>(PlayerState))
        {
            MyPlayerState->RemoveAllSpawnedAttributes();
        }
    }
}

// 游戏实例中
void UMyGameInstance::Shutdown()
{
    // 游戏关闭时全局清理
    UWorld* World = GetWorld();
    if (World)
    {
        for (TActorIterator<AActor> It(World); It; ++It)
        {
            if (IAttributeInterface* AttributeActor = Cast<IAttributeInterface>(*It))
            {
                AttributeActor->RemoveAllSpawnedAttributes();
            }
        }
    }
}

6. 性能优化实践

对象池模式

cpp 复制代码
// 避免频繁的内存分配释放
void UAttributeManager::RemoveAllSpawnedAttributes()
{
    for (UAttributeSet* AttributeSet : SpawnedAttributes)
    {
        // 不立即销毁,而是重置并回收到对象池
        AttributeSet->Reset();
        AttributePool.Return(AttributeSet);
    }
    SpawnedAttributes.Empty();
}

UAttributeSet* UAttributeManager::SpawnAttribute(TSubclassOf<UAttributeSet> AttributeClass)
{
    UAttributeSet* AttributeSet = nullptr;
    
    // 优先从对象池获取
    if (AttributePool.CanProvide(AttributeClass))
    {
        AttributeSet = AttributePool.Get(AttributeClass);
    }
    else
    {
        // 池中无可用对象时创建新实例
        AttributeSet = NewObject<UAttributeSet>(this, AttributeClass);
    }
    
    SpawnedAttributes.Add(AttributeSet);
    return AttributeSet;
}

7. 调试和开发工具

开发者命令

cpp 复制代码
// 控制台命令用于调试
void AMyCheatManager::RemoveAllAttributes()
{
    if (APawn* Pawn = GetPlayerPawn())
    {
        if (IAttributeInterface* AttributePawn = Cast<IAttributeInterface>(Pawn))
        {
            AttributePawn->RemoveAllSpawnedAttributes();
            UE_LOG(LogTemp, Warning, TEXT("Removed all spawned attributes"));
        }
    }
}

// 在编辑器中测试
void UMyDeveloperSettings::TestAttributeCleanup()
{
    UWorld* World = GEngine->GetWorldContexts()[0].World();
    // 测试属性清理功能...
}

这些实际应用展示了 RemoveAllSpawnedAttributes() 在游戏开发中的关键作用,特别是在管理动态游戏状态、防止内存泄漏和确保系统稳定性方面。

相关推荐
QT 小鲜肉2 小时前
【Linux常用命令大全】在 Linux 系统下 Git + Vim编辑器常用指令完全指南(亲测有效)
linux·开发语言·c++·笔记·git·编辑器·vim
oioihoii3 小时前
现代C++:一场静默的革命,告别“C with Classes”
c语言·jvm·c++
普通网友3 小时前
C++中的组合模式
开发语言·c++·算法
江公望4 小时前
Qt QByteArray类型,10分钟讲清楚
开发语言·c++·qt
2501_941111464 小时前
C++中的组合模式变体
开发语言·c++·算法
普通网友4 小时前
单元测试在C++项目中的实践
开发语言·c++·算法
p66666666685 小时前
【☀Linux驱动开发笔记☀】新字符设备驱动开发_02
linux·嵌入式硬件·学习
沐怡旸5 小时前
【穿越Effective C++】条款22:将成员变量声明为private——封装的边界与设计的自由
c++
笨鸟笃行5 小时前
百日挑战——单词篇(第二十四天)
学习