After following the Event Dispatchers and Delegates quickstart for both Blueprints and C++, I wanted to extend the C++ version to also trigger explosions, which the Blueprint quickstart does but the C++ quickstart omits. Additionally, I wanted the communication for the explosion trigger to be effected through the Event Graph rather than having to build an Explosion C++ class.
In short, an acceptable solution must:
- Allow multiple C++ classes to execute custom code when the boss dies; AND
- Allow multiple Blueprint classes to execute custom Event Graph logic when the boss dies; AND
- Allow the Unreal Editor user to select a (possibly different) boss for each instance from within the applicable Details pane (i.e. selecting the Boss Died Reference should work like it does in the quickstart); AND
- Be closer to optimal than my solution in terms of memory footprint, speed, quality, etc.
What I had hoped to do was simply expose the OnBossDied delegate via a UFUNCTION or UPROPERTY and have it work for both Blueprint and C++ bindings, but I couldn’t make that approach work without compilation errors. So, I implemented the following working solution instead.
Changes to BossActor.h:
// Declare two different delegates outside of the class
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnBossDiedBPDelegate);
DECLARE_MULTICAST_DELEGATE(FOnBossDiedCppDelegate);
// ...
protected:
// Add BlueprintCallable to the UFUNCTION for the code-based event handler
UFUNCTION(BlueprintCallable, Category="Boss Died Notifications")
void HandleBossDiedEvent();
public:
// Add a UPROPERTY to the Blueprint delegate
UPROPERTY(BlueprintAssignable, Category = "Boss Died Notifications")
FOnBossDiedBPDelegate OnBossDiedBP;
FOnBossDiedCppDelegate OnBossDiedCpp;
Changes to BossActor.cpp:
// Switch to Broadcast() because we are using multicast, and
// call it on both delegate types
void ABossActor::HandleBossDiedEvent()
{
OnBossDiedBP.Broadcast();
OnBossDiedCpp.Broadcast();
}
Changes to DoorActor.cpp:
// Rename OnBossDied to OnBossDiedCpp, and
// call AddUObject() instead of BindUObject()
BossActorReference->OnBossDiedCpp.AddUObject(this, &ADoorActor::BossDiedEventFunction);
Save and compile the above changes, and then follow the steps from the Blueprint version of the quickstart for the Blueprint_Effect_Explosion asset. As stated at the beginning, my solution works fine on my machine. When we simulate the boss dying by moving the player character into the BP_BossActor collision box, the door opens, and the explosions fire. Nonetheless, this two-delegate solution feels awkward and silly. There must be a way to use a single delegate to accomplish the same goal, right?