How can I use an interface to pass a value to another class?

[EDIT] - SOLVED! The solution turned out to simply be adding a comma followed by the desired variable/value.

if(ObjectHit.GetActor()->GetClass()->ImplementsInterface(UInteractInterface::StaticClass()))
{
	IInteractInterface::Execute_GetInteractable(ObjectHit.GetActor(), bSomeBoolean);
}

I just hadn’t actually tried compiling this because when I briefly wrote it this way, Visual Studio threw an error message at me before I even hit build. Womp womp. Moral of the story is don’t always trust what the IDE says I guess.

----- Original Post -----

I’m writing an interface to handle interaction events between the player character class and any class the player can interact with, such as items that can be physically picked up in the game world. Right now in my item base class, I’ve got a boolean variable bInteractable that’s acting as a simple flag to designate that the item can currently be interacted with. I’ve got a pair of functions, bool GetInteractable() and void SetInteractable(), that I’m using to check and toggle this flag.

Right now, the GetInteractable() function is working fine. It’s SetInteractable() I can’t figure out. I’m trying to set it up so that I can pass a parameter from my player character class to update bInteractable in the item base class as follows:

The function in IInteractInterface.h

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interaction")
void SetInteractable(bool UpdateInteractable);

The boolean flag and function in ItemBase.h

UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Interaction")
bool bInteractable = true;

//... some other code

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interaction")
void SetInteractable();
virtual void SetInteractable_Implementation(bool UpdateInteractable) override;

And then using the function to change the boolean in ItemBase.cpp

void AItemBase::SetInteractable_Implementation(bool UpdateInteractable)
{
	AItemBase::bInteractable == UpdateInteractable;
}

So far I’m reasonably sure all that should work (although I haven’t gotten to actually run it yet for reasons below).

Next, in my player character class, I’m doing a line trace to get the desired instance of my item base class, and calling the functions in the interface for that instance of the item. Currently, this code (which actually calls the GetInteractable() function, but the one for SetInteractable() should look similar) works fine:

In PlayerCharacter.cpp

if(ObjectHit.GetActor()->GetClass()->ImplementsInterface(UInteractInterface::StaticClass()))
{
	IInteractInterface::Execute_GetInteractable(ObjectHit.GetActor());
}

.

HERE’S THE PART I NEED HELP WITH ! ! !

.

What I can’t figure out is how to actually pass a boolean value along to the SetInteractable() function in the item base class. Normally this would be as simple as putting the name of another boolean variable in the parentheses in the function call, but you’ll notice in the example above that those are being used to call the specific item (GetActor()). In other words:

In PlayerCharacter.cpp

if(ObjectHit.GetActor()->GetClass()->ImplementsInterface(UInteractInterface::StaticClass()))
{

IInteractInterface::Execute_SetInteractable(ObjectHit.GetActor()); // <-- This one that actually works

// ^^^ These two function calls seem to be mutually exclusive, and I don't know how to resolve them.  Is there syntax that will allow for this, or am I fundementally missing something about how interfaces work? vvv //

IInteractInterface::Execute_SetInteractable(bSomeOtherBoolean UpdateInteractable); // <-- This one doesn't work but is how all my previous C++ experience tells me it *should* work, but then I wouldn't know where to put the reference to ObjectHit

}

I’ve been strung out trying to wrap my head around interfaces in Unreal for like three days now, and this is the last major piece of the puzzle for me. Any help would be INFINITELY appreciated!

The SetInteractable function isn’t declared as virtual in the interface, also the method in your itembase isn’t declared as an override, nor do the functions in the itembase.h even share the same return type with the one declared in the interface

Whoops, good catch on the return type in the interface! Had copied it over from GetInteractable() and forgot to change it. (I’m sure the compiler would have caught me on that, but like I said I haven’t been able to compile yet with the SetInteractable() function in place!). Edited the original post to make it void.

So the reason the SetInteractable() function isn’t declared as virtual in the interface is because none of the guides I was referencing to write this had things set up that way. They all seemed to agree that the “correct” way to implement this is to simply declare it with just the return type in the interface, then again in the header for the actor implementing the interface, and then to declare it with virtual, override, and the suffix “_Implementable” immediately following that. (IIRC this has to do with the fact that these examples as well as my own code are using the BlueprintNativeEvent specifier in the UFUNCTION macro).

Example 1
Example 2

But like I said, the code compiles fine and behaves as intended with the GetInteractable() function.

Interactable.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InteractInterface.h"
#include "Interactable.generated.h"

UCLASS()
class YOUR_API AInteractable : public AActor , public IInteractInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AInteractable();

	UPROPERTY()
	USceneComponent* Root;


protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;


	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void SetInteractable(bool UpdateInteractable);
	virtual void SetInteractable_Implementation(bool UpdateInteractable);
};

Interactable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "Interactable.h"

// Sets default values
AInteractable::AInteractable()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	Root = CreateDefaultSubobject<USceneComponent>("Root");
	SetRootComponent(Root);
}

// Called when the game starts or when spawned
void AInteractable::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AInteractable::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}


void AInteractable::SetInteractable_Implementation(bool UpdateInteractable)
{
}


InteractInterface.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "InteractInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInteractInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class YOUR_API IInteractInterface
{
	GENERATED_BODY()

public:
		UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interaction")
		void SetInteractable(bool UpdateInteractable);


	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
};

And later implementation example with passed true

	if (Character->GetClass()->ImplementsInterface(UInteractInterface::StaticClass())) {
		IInteractInterface::Execute_SetInteractable(Character,true);				
	}

1 Like

Wow, that… actually did it!

I had actually tried writing that in my code at one point, but I didn’t bother trying to compile because Visual Studio threw a preemptive error warning at me for it. Which I should’ve known to test anyway because it’s not the first false-positive I’ve gotten from IntelliSense not really understanding what’s going on with interfaces :sweat_smile:

Thanks for your help though! Guess the moral here is I need to start thinking about throwing down some cash for ReSharper or something :upside_down_face:

With interfaces just remember to pass in what implemented the interface as the first parameter.

The syntax is sort of reversed as you are calling the interface passing in the object and then the needed arguments. Hence the decoupling mechanism where you can swap out the subject of the call.