If you have been developing in UE4 for some time you have probably stumbled into delegates.
What is a delegate? Delegates in two words are a UE4 implementation of the famous Observer template pattern. It allows code clients (or observers) to subscribe to some events. A dispatcher does not even know that something is listening to it. It just broadcasts events. This is a very powerful pattern – it makes your code less coupled.
There is a documentation page dedicated to delegates in official UE4 documentation: https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Delegates/
But as usual with Epic documentation it is far from being helpful. I still cannot get used to them and always consult with various tutorials if I need to know what delegate to use in a certain situation. So the main goal of this post is to answer my own question:
What delegate do I use now?
Static Delegates
The simplest delegate you may use is a static delegate and you can only bind one listener to it.
Suppose, you need to broadcast an event when you fire a gun. Then this is how you define and declare it:
DECLARE_DELEGATE(FStaticDelegate);
class FFireHandler
{
void OnFire();
}
class AGunner : public ACharacter
{
FFireHandler* FireHandler;
FStaticDelegate OnFireDelegate;
}
And then how you use it:
FireHandler = new FFireHandler();
OnFireDelegate.BindRaw(FireHandler, &FFireHandler::OnFire);
...
OnFireDelegate.ExecuteIfBound();
If you want to bind the delegate to a UObject
method, then use OnFireDelegate.BindUObject
method.
When to use it?
When you need the fastest way to let a listener know that something happened.
Multicast Delegates
Static delegates despite the fact that they are most performant have a disadvantage – they can have only one listener. To overcome this problem you need to use static multicast delegates. Its AddRaw
method allows adding multiple listeners:
DECLARE_MULTICAST_DELEGATE(FStaticMulticastDelegate);
class FFireHandler
{
void OnFire();
}
class AGunner : public ACharacter
{
FFireHandler* FireHandler;
FFireHandler* FireHandler2;
FStaticMulticastDelegate OnFireDelegate;
}
And this is how you use it:
FireHandler = new FFireHandler();
FireHandler2 = new FFireHandler();
OnFireDelegate.AddRaw(FireHandler, &FFireHandler::OnFire);
OnFireDelegate.AddRaw(FireHandler2, &FFireHandler::OnFire);
...
OnFireDelegate.Broadcast();
Notice here, that in order to broadcast an event you use Broadcast
method. You don’t need to check if there is anything bound to a delegate: multicast delegates operate with weak pointers.
When to use it?
Use it if you need more than one listener.
Dynamic Delegates
Dynamic delegates are the least interesting. The only difference between them and static delegates is that they can be serialized and also they are slower.
You define them as follows:
DECLARE_DYNAMIC_DELEGATE(FDynamicDelegate);
class AGunner : public ACharacter
{
FDynamicDelegate OnFireDelegate;
UFUNCTION()
void OnFireHandler();
}
Important here is that you annotate a handler function with UFUNCTION
macro!
And this is how you use it:
OnFireDelegate.BindDynamic(this, &AGunner::OnFireHandler)
...
OnFireDelegate.ExecuteIfBound();
When to use it?
When you deal with serialization.
Dynamic Multicast Delegates
And finally the most powerful, yet the slowest delegates: dynamic multicast delegates. They have characteristics of both multicast and dynamic delegates and that allows using them in Blueprints!
This is how you define them and declare them:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDynamicMulticastDelegate);
class AGunner : public ACharacter
{
UPROPERTY(BlueprintAssignable);
FDynamicMulticastDelegate OnFireDelegate;
}
Annotate the delegate with UPROPERTY(BlueprintAssignable)
macro to make it visible from a blueprint:
Of course, you can also bind a C++ function to the delegate like this:
OnFireDelegate.AddDynamic(this, &AGunner::OnFireHandler)
...
OnFireDelegate.Broadcast();
As with a regular dynamic delegate, mark the function with UFUNCTION
macro.
When to use it?
When you need to call a delegate from a blueprint.
I hope this article will help you next time when you are scratching your head and thinking what delegate you would use. Use this as a cheat sheet!
The most complete and easy-to-understand explanation. Thank you.
Give that man a beer! The clearest and most precise information I found on this subject, thank you very much
Thanks, man!
Awesome