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
相关产品推荐
相关产品推荐

