How it works...

Inside our GameMode header, we declare a type of delegate that doesn't take any parameters, called FStandardDelegateSignatureWe then create an instance of the delegate as a member of our GameModeBase class.

We add a PointLight component inside of the DelegateListener so that we have a visual representation of the delegate being executed that we can turn on later on. In the constructor, we initialize our PointLight, and then disable it. To make it easier to see, we also change the color to blue.

We override BeginPlay. We first call the parent class's implementation of BeginPlay(). Then, we get the game world, retrieving the GameMode class using GetGameMode()Casting the resulting AGameMode* to a pointer of our GameMode class requires the use of the Cast template function. We can then access the delegate instance member of the GameMode and bind our EnableLight function to the delegate so that it will be called when the delegate is executed. In this case, we are binding to UFUNCTION(), so we use BindUObject.

If we had wanted to bind to a plain C++ class function, we would have used BindRaw. If we had wanted to bind to a static function, we would have used BindStatic(). If you're using these, you must be very careful and unbind them manually when an object is being destroyed. It's the same as using naked C++ memory allocation. When it comes to UE4, the general rule of thumb is to use a UObject wherever possible. It saves a lot of headaches!

When TriggerVolume overlaps the player, it retrieves GameMode, then calls ExecuteIfBound on the delegate. ExecuteIfBound checks that there's a function bound to the delegate, and then invokes it for us. The EnableLight function enables the PointLight component when it's invoked by the delegate object.