I am trying to implement an interaction system via an interface but am having trouble figuring out how to call functions in my interface via C++. I am able to call these interface functions in Blueprints with the message nodes.
Some answers online talk about using Execute_* functions but I can’t find any clear description on how to do this. I have tried casting with Cast<>() and InterfaceCast but these cause my project to crash.
Specifically, what I am trying to do is run a trace to see if there are any actors in front of the player pawn that implement my InteractableInterface. And then I want to be able to call the Interact(…) function on that actor. My InteractableInterface code is shown below.
if (YourActor->GetClass()->ImplementsInterface(UInteractableInterface::StaticClass()))
{
IInteractableInterface::Execute_Interact(YourActor); // This is the Execute_* function. The asterisk means your function name. :)
}
Upon compilation I get Execute_Interact is not a member of IInteractableInterface. I found another error in my code and I was able to cast to IInteractable Interface successfully with Cast < InteractableInterface > (ActorRef);
.h (blueprint callable interface, but implemented in c++)
#pragma once
//this is important for the auto-generated executed functions.
#include "EntityInterface.generated.h"
/** Interface for actors which can be associated with teams */
/** Class needed to support InterfaceCast<IToStringInterface>(Object) */
UINTERFACE(meta = (CannotImplementInterfaceInBlueprint = true))
class UEntityInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class IEntityInterface
{
GENERATED_IINTERFACE_BODY()
/** returns the owner number of the actor (0=world, otherwise it's a player) */
UFUNCTION(BlueprintCallable, Category = "ImperoEntities")
virtual int32 GetOwnerNum() const = 0;
/** sets the owner number of the actor */
UFUNCTION(BlueprintCallable, Category = "ImperoEntities")
virtual void SetOwnerNum(const int32 OwnerNum) = 0;
/** returns the id number of the actor */
UFUNCTION(BlueprintCallable, Category = "ImperoEntities")
virtual int32 GetEntityId() const = 0;
/** sets the id number of the actor */
UFUNCTION(BlueprintCallable, Category = "ImperoEntities")
virtual void SetEntityId(const int32 NewEntityId) = 0;
/** Remove the given amount from entity's healt (net unsafe) */
UFUNCTION(BlueprintCallable, Category = "ImperoEntities")
virtual void ApplyDamage(int32 Amount) = 0;
};
another .h (Blueprint implementable events)
#pragma once
#include "SelectableInterface.generated.h"
/** Interface for actors which can be associated with teams */
/** Class needed to support InterfaceCast<IToStringInterface>(Object) */
UINTERFACE()
class USelectableInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class ISelectableInterface
{
GENERATED_IINTERFACE_BODY()
/** tries to select actor */
UFUNCTION(BlueprintImplementableEvent, Category = Selection)
void OnSelectionGained();
/** tries to deselect actor */
UFUNCTION(BlueprintImplementableEvent, Category = Selection)
void OnSelectionLost();
UFUNCTION(BlueprintImplementableEvent, Category = Commands)
bool DoOnTargetEvent(const TScriptInterface<IEntityInterface>& Target, const TEnumAsByte<EJobType::Type>& JobType);
};
.cpp (tip: you can implement more than one interface in only 1 cpp, as u can see)
//i have multiple targets at once
TArray<IEntityInterface*> Subjects;
//fill the array somehow
//and then call the function on the interface
//note that this function is only declared in the interface,
//the implementation is on Blueprints side
for (IEntityInterface* Subject : Subjects)
{
ISelectableInterface* s = Cast<ISelectableInterface>(Subject);
//note that actually i'm using 2 different interfaces
if (s)
{
s->Execute_DoOnTargetEvent(Cast<UObject>(s), Target, Job);
}
}
I forgot sorry, note that for the execute function you have to provide the UObject context (the Object on which you’re calling the function, as a child of UObject: i used a cast to a generic UObject, but if you already have a pointer of your class type, you can use that directly) as first parameter.
Execute_Interact was just an example i posted. You need to replace Interact with your function name. For example, if your function name is MyFunction then it should be Execute_MyFunction.
The Execute_* static function only exists on BlueprintImplementable/BlueprintNativeEventUFUNCTIONs. By using CannotImplementInterfaceInBlueprint, Cast<InteractableInterface> is the correct approach.