Unreal Engine 使用 AddDynamic 崩溃

Unreal Engine crash with AddDynamic

我在绑定 OnAudioFinished 委托时遇到问题。

搜索了一段时间,但还没有找到合适的答案。我关注了这个 answer!

我的代码编译没有任何错误,但是当我的项目加载时它崩溃并出现以下错误:

UE4Editor_!TBaseDynamicMulticastDelegate<FWeakObjectPtr,void>::__Internal_AddDynamic<UAudioController>() [d:\path\delegates\delegatesignatureimpl.inl:1140]
UE4Editor_Project!UAudioController::UAudioController() [d:\path\private\audiocontroller.cpp:17]
UE4Editor_Project!InternalConstructor<UAudioController>()

我所理解的是构造函数破坏了我的引擎,但我不知道为什么会这样。这是我负责此绑定的代码。

.h

static UAudioComponent* AudioComponent;

public:
    UAudioController();


void SoundFinished();

.cpp

UAudioController::UAudioController()
{
    AudioComponent->OnAudioFinished.AddDynamic(this, &UAudioController::SoundFinished);

}

void UAudioController::SoundFinished()
{
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, TEXT("Audio Finished trigger"));
}

在 UE 中,属性在构造函数期间未正确初始化 运行。它们是在调用 PostInitProperties 时(从 CDO 加载后)。

此外,您应该问问自己是否需要 static class。如果你需要 Singleton,你可以将其存储在 GameInstance 中。它更安全,尤其是在 UE 环境中(你不能有静态 UPROPERTY() 字段等)

我认为在 BeginPlay 期间绑定此事件应该就足够了。删除是一个很好的做法,尽管在使用 Dynamic binding

时不是必需的
// AudioController.h
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReasonType) override;

// AudioController.cpp
void UAudioController::BeginPlay() {
    Super::BeginPlay();
     AudioComponent->OnAudioFinished.AddDynamic(this, &UAudioController::SoundFinished);
}

void UAudioController::EndPlay(const EEndPlayReason::Type EndPlayReasonType) {
     AudioComponent->OnAudioFinished.RemoveDynamic(this, &UAudioController::SoundFinished);  
    Super::EndPlay(EndPlayReasonType);
}

编辑: 因为你用 Controller 后缀命名你的 class,我想这将是单次出现水平的演员。所以你不需要有静态指针(它可能会被破坏 - 同样,这是 UE 的特殊性),只需将 AudioComponent 作为 public 您控制器中的成员:

// AudioController.h
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "My Audio Conmponent", meta = (AllowPrivateAccess = "true"))
    UAudioComponent* AudioComponent;

然后在构造函数中正确初始化它:

UAudioController::UAudioController()
    : Super()
{
    AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("MyAudioComponent"));
}

UAudioController::UAudioController(const class FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("MyAudioComponent"));
}

您的组件将被正确创建并且绑定函数将按预期执行。

此外,正如@JKovalsky 提到的,在使用 Dynamic 委托时,您的 SoundFinished 方法必须用 UFUNCTION() 宏标记。