You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE4场景Actor销毁追踪咨询:如何通过TActorIterator实现

解决UE中追踪Spawner生成Actor销毁时机的问题

你的思路误区在于:TActorIterator只能遍历当前场景中存活的Actor,它根本不会包含已经被销毁的Actor,所以你没法直接用它判断“哪些原本存在的Actor消失了”——你得先把Spawner生成的所有Actor记录下来,再和当前状态做对比,或者更高效地绑定销毁回调实时通知。

下面给你两种可行的方案,从简单到高效:

方案一:定期轮询检查(适合小规模Actor场景)

步骤1:保存生成的Actor弱指针列表

在你的Spawner类里,先声明一个用来存储所有生成Actor的二维数组(用弱指针避免悬空指针):

// Spawner类的头文件
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Spawner.generated.h"

UCLASS()
class YOURPROJECT_API ASpawner : public AActor
{
    GENERATED_BODY()
    
public:    
    ASpawner();

protected:
    virtual void BeginPlay() override;

public:    
    virtual void Tick(float DeltaTime) override;

    // 存储生成的Actor二维数组,用弱指针安全判断有效性
    UPROPERTY()
    TArray<TArray<TWeakObjectPtr<AActor>>> SpawnedActors2D;

    // 可选:网格尺寸,根据你的需求调整
    UPROPERTY(EditAnywhere, Category = "Spawn Settings")
    int32 GridWidth = 5;

    UPROPERTY(EditAnywhere, Category = "Spawn Settings")
    int32 GridHeight = 5;

    UPROPERTY(EditAnywhere, Category = "Spawn Settings")
    TSubclassOf<AActor> ActorToSpawn;
};

步骤2:生成Actor时存入列表

在BeginPlay或者你的生成函数里,把Spawn的Actor添加到数组中:

void ASpawner::BeginPlay()
{
    Super::BeginPlay();

    if (!ActorToSpawn) return;

    // 生成二维数组Actor
    for (int32 X = 0; X < GridWidth; X++)
    {
        TArray<TWeakObjectPtr<AActor>> CurrentRow;
        for (int32 Y = 0; Y < GridHeight; Y++)
        {
            // 这里替换成你的生成位置逻辑
            FVector SpawnLocation = GetActorLocation() + FVector(X * 200.f, Y * 200.f, 0.f);
            AActor* NewActor = GetWorld()->SpawnActor<AActor>(ActorToSpawn, SpawnLocation, FRotator::ZeroRotator);
            
            if (NewActor)
            {
                CurrentRow.Add(TWeakObjectPtr<AActor>(NewActor));
            }
        }
        SpawnedActors2D.Add(CurrentRow);
    }
}

步骤3:定期检查销毁状态

可以在Tick里或者用Timer来检查,这里以每帧检查为例(如果Actor多的话,建议改成Timer间隔检查):

void ASpawner::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    // 遍历二维数组,检查每个Actor是否存活
    for (int32 X = 0; X < SpawnedActors2D.Num(); X++)
    {
        auto& CurrentRow = SpawnedActors2D[X];
        // 倒序遍历避免移除元素时索引混乱
        for (int32 Y = CurrentRow.Num() - 1; Y >= 0; Y--)
        {
            TWeakObjectPtr<AActor> WeakActor = CurrentRow[Y];
            if (!WeakActor.IsValid())
            {
                // 触发销毁提示
                UE_LOG(LogTemp, Warning, TEXT("Actor at grid (%d,%d) has been destroyed!"), X, Y);
                // 从数组中移除无效的弱指针,避免重复提示
                CurrentRow.RemoveAt(Y);
            }
        }
    }
}

方案二:绑定销毁回调(高效实时通知)

如果不想轮询,更高效的方式是给每个生成的Actor绑定OnDestroyed事件,这样Actor一被销毁就立刻触发通知:

步骤1:添加回调函数声明

在Spawner的头文件里添加一个UFUNCTION作为回调:

UFUNCTION()
void OnSpawnedActorDestroyed(AActor* DestroyedActor);

步骤2:生成Actor时绑定回调

修改生成逻辑,绑定销毁事件:

void ASpawner::BeginPlay()
{
    Super::BeginPlay();

    if (!ActorToSpawn) return;

    for (int32 X = 0; X < GridWidth; X++)
    {
        TArray<TWeakObjectPtr<AActor>> CurrentRow;
        for (int32 Y = 0; Y < GridHeight; Y++)
        {
            FVector SpawnLocation = GetActorLocation() + FVector(X * 200.f, Y * 200.f, 0.f);
            AActor* NewActor = GetWorld()->SpawnActor<AActor>(ActorToSpawn, SpawnLocation, FRotator::ZeroRotator);
            
            if (NewActor)
            {
                // 绑定销毁回调,Actor销毁时自动调用OnSpawnedActorDestroyed
                NewActor->OnDestroyed.AddDynamic(this, &ASpawner::OnSpawnedActorDestroyed);
                CurrentRow.Add(TWeakObjectPtr<AActor>(NewActor));
            }
        }
        SpawnedActors2D.Add(CurrentRow);
    }
}

步骤3:实现回调函数

在源文件里实现回调,处理销毁通知:

void ASpawner::OnSpawnedActorDestroyed(AActor* DestroyedActor)
{
    UE_LOG(LogTemp, Warning, TEXT("Spawned Actor '%s' has been destroyed!"), *DestroyedActor->GetName());

    // 可选:从二维数组中移除该Actor的记录
    for (auto& Row : SpawnedActors2D)
    {
        Row.Remove(TWeakObjectPtr<AActor>(DestroyedActor));
    }
}

关键注意点

  • 必须用弱指针:不能直接存AActor*,因为Actor被销毁后强指针会变成野指针,访问会导致崩溃。TWeakObjectPtr的IsValid()方法可以安全判断Actor是否还存活。
  • 回调的生命周期问题:如果Spawner可能先于生成的Actor被销毁,记得在Spawner的EndPlay里解除所有绑定,避免悬空回调导致崩溃:
void ASpawner::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    Super::EndPlay(EndPlayReason);

    // 解除所有Actor的销毁回调绑定
    for (auto& Row : SpawnedActors2D)
    {
        for (auto WeakActor : Row)
        {
            if (WeakActor.IsValid())
            {
                WeakActor->OnDestroyed.RemoveDynamic(this, &ASpawner::OnSpawnedActorDestroyed);
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者neoluna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:57:51