Expose an interface to blueprint
NOTE: This tutorial is largely out of date, recommend reading this instead
Interfaces in C++
We will create a simple interface that you can use in your blueprints. As you can see in the picture above we will create a simple event called
On Interact
which exposes your interface "clicked" with argument type
ITargetInterface
. Note that this argument is only needed in this specific example. If you make your own class with your own event, you can make events with an optional number of arguments. With this interface in place we will be able to call it's functions like
GetHealth
.
Header file:
#pragma once
#include "TargetInterface.generated.h"
UINTERFACE(MinimalAPI)
class UTargetInterface :
public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class ITargetInterface{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintImplementableEvent, meta=(FriendlyName = "On Interact"))
void OnInteract(const TScriptInterface<ITargetInterface> &clicked);
virtual float GetHealth();
};
.cpp file:
#include "YourProject.h"
#include "TargetInterface.h"
UTargetInterface::UTargetInterface(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP){
}
// Give GetHealth a default implementation
float ITargetInterface::GetHealth(){
return 0.0f;
}
The important part here is
UFUNCTION(BlueprintImplementableEvent, meta=(FriendlyName = "On Interact"))
void OnInteract(const TScriptInterface<ITargetInterface> &clicked);
1.) BlueprintImplementableEvent turns your function into a blueprint event. This event will be called in blueprint when ever you call it in c++.
2.) void OnInteract(const TScriptInterface<ITargetInterface> &clicked); . Sometimes simple events are not enough for example in this case we want to know who has started the OnInteract event.
3.) The most important part is " const TScriptInterface<ITargetInterface> &clicked ". We have to wrap our interface inside of an TScriptInterface to expose it to blueprint.
To trigger the event you can from within your C++ code call the function Execute_OnInteract. It always takes the instance of your class as an argument + the optional arguments you defined. In our case this is a TScriptInterface<ITargetInterface> object. Below is the example code, where we have created an instance named actor. We will generate the necessary argument "s" and then call the Execute_OnInteract function.
auto t = InterfaceCast<ITargetInterface>(actor);
if (t != nullptr){
TScriptInterface<ITargetInterface> s = TScriptInterface<ITargetInterface>();
s.SetObject(actor);
s.SetInterface(t);
t->Execute_OnInteract(actor,s);
}
InterfaceCast tries to convert your actor to an ITargetInterface. In this case the variable "t" will be null if the cast has failed. The next step is to wrap our actor who implements our ITargetInterface in an TScriptInterface. You do this by creating an TScriptInterface with the default consturctor and use the SetObject method.
Now the most important part here is that you should not call the method OnInteract because this will result in an runtime error. Instead you need to call the generated utility function which is called Execute_YourFunctionName in this case it is called Execute_OnInteract . The first argument is always the UObject and the following argument are the arguments of your function.
In our case we defined
void OnInteract(const TScriptInterface<ITargetInterface> &clicked)
So the type signature will look like this
Execute_OnInteract(UObject *object, const TScriptInterface<ITargetInterface> &clicked);
At this point you can already use your event in your blueprints. The problem is that you have no functions that are working with your newly created interface. Let's fix this.
Header code:
#pragma once
#include "GameFramework/Actor.h"
#include "TargetInterface.h"
#include "TargetInterfaceBPFunctionLibrary.generated.h"
/**
*
*/
UCLASS()
class UTargetInterfaceBPFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
UFUNCTION(BlueprintCallable, Category="TargetInterface")
static float GetHealth(const TScriptInterface<ITargetInterface> &target);
};
.cpp code:
#include "project.h"
#include "TargetInterfaceBPFunctionLibrary.h"
UTargetInterfaceBPFunctionLibrary::UTargetInterfaceBPFunctionLibrary(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
}
float UTargetInterfaceBPFunctionLibrary::GetHealth(const TScriptInterface<ITargetInterface> &target)
{
return target->GetHealth();
}
That's it. Now you can access your interface inside of your blueprints.