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

UE5中销毁Actor导致引擎崩溃的原因排查求助

问题:碰撞触发Actor自销毁时UE引擎冻结崩溃

我做了一个带碰撞触发自销毁逻辑的Actor,只调用UE_LOG时碰撞功能完全正常,但一调用Destroy(),引擎就会先冻结然后崩溃。已经排除了蓝图设置的问题,确定是代码层面的问题。

附上C++代码:

#include "MechanicMike_BreakableBlock.h"

#include "MechanicMike.h"
#include "PaperSpriteComponent.h"
#include "Components/BoxComponent.h"

// Sets default values
AMechanicMike_BreakableBlock::AMechanicMike_BreakableBlock()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    MySprite = CreateDefaultSubobject<UPaperSpriteComponent>(TEXT("Breakable Block"));
    MyBreakableTrigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Breakable Trigger"));
    RootComponent = MyBreakableTrigger;
    MySprite->SetupAttachment(RootComponent);
}

// Called when the game starts or when spawned
void AMechanicMike_BreakableBlock::BeginPlay()
{
    Super::BeginPlay();
    MyBreakableTrigger->OnComponentHit.AddDynamic(this, &AMechanicMike_BreakableBlock::OnBlockHit);
    
}

// Called every frame
void AMechanicMike_BreakableBlock::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

void AMechanicMike_BreakableBlock::OnBlockHit(UPrimitiveComponent* HitComponent, AActor* OtherActor,
    UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
    if (OtherActor->IsA(AMechanicMike::StaticClass()))
    {
        BlockDestroy();
    }
}

void AMechanicMike_BreakableBlock::BlockDestroy()
{
    if (!IsPendingKillPending())
    {
        Destroy();
    }
}

原因分析与修复方案

核心问题:物理线程与游戏线程冲突

OnComponentHit回调是在物理线程中执行的,而Destroy()属于游戏线程的操作。直接在物理线程调用游戏线程的销毁逻辑,会导致线程同步异常,进而引发引擎冻结甚至崩溃。

修复方法:将销毁操作转移到游戏线程

可以通过两种方式实现:

方案1:延迟到下一帧执行销毁

使用定时器让销毁逻辑在游戏线程的下一帧执行:

void AMechanicMike_BreakableBlock::BlockDestroy()
{
    if (!IsPendingKillPending())
    {
        GetWorld()->GetTimerManager().SetTimerForNextTick([this]()
        {
            if (!IsPendingKillPending())
            {
                Destroy();
            }
        });
    }
}

方案2:显式投递到游戏线程

用AsyncTask直接把销毁任务投递到游戏线程:

void AMechanicMike_BreakableBlock::BlockDestroy()
{
    if (!IsPendingKillPending())
    {
        AsyncTask(ENamedThreads::GameThread, [this]()
        {
            if (!IsPendingKillPending())
            {
                Destroy();
            }
        });
    }
}

额外优化:关闭无用的Tick

你的Actor开启了PrimaryActorTick.bCanEverTick = true,但Tick函数没有任何业务逻辑,建议关闭它来减少不必要的性能开销:

// 在构造函数中修改
PrimaryActorTick.bCanEverTick = false;

验证

替换BlockDestroy函数后,测试碰撞触发销毁,引擎应该不会再出现冻结崩溃的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:25:22