简体   繁体   中英

Unreal Engine crash with AddDynamic

I have a problem with binding OnAudioFinished delegate.

Searched for some time but haven't find good answer yet. I've followed this answer !

My code compiles without any error at all, however when my project is loading it crashes with this errors:

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>()

What I do understand is that constructor crushes my engine, but i don't know why is that happening. Here is my code that is responsible for this binding.

.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"));
}

In UE, properties are not properly initialized during constructor run. They are when PostInitProperties is called (after load from CDO).

Also you should ask yourself if static class is necessary. If You need Singleton, you can store this in GameInstance . It is safer, especially in UE environment (you can't have static UPROPERTY() field etc.)

I believe that binding this event during BeginPlay should be sufficient. Removing is good practice, although not necesarry when using 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);
}

EDIT: Since you named your class with Controller suffix, I suppose that this will be single occurence of this actor in level. So you don't need to have static pointer (it could get destroyed - again, this is UE speciality), just simply have AudioComponent as a public member in your controller:

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

and then correctly initialize it in constructor:

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

or

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

Your component will be properly created and binded function will be executed as expected.

Also, as @JKovalsky mentioned, your SoundFinished method must be marked with UFUNCTION() macro when using Dynamic delegates.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM