Could use some interface help

So i came up with neat little system where i do 2 things

  1. Create a Usable interface with methods:
    void Interact(AActor* UsingActor)
    void SetStatus(AActor* UsingActor, bool Usable) //For telling an actor that its usable or not to blink or something
    So that i can add it to all the actors in the level to make them instantly usable by the another thing
  2. InteractionComponent that inherits from sphere component that will work with actors with Usable interface by Setting their statuses and raycasting.

in .cpp i have


void UInteractionComponent::OnPotentialUsableCollisionEnter(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
	IIUsable* PotentialUsable = Cast<IIUsable>(OtherActor);
	if (PotentialUsable)
	{
		PotentialUsable->SetStatus(GetOwner(), true);
		UsablesInRange.Add(PotentialUsable);
	}
}

void UInteractionComponent::OnPotentialUsableCollisionEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	IIUsable* PotentialUsable = Cast<IIUsable>(OtherActor);
	if (PotentialUsable)
	{
		PotentialUsable->SetStatus(GetOwner(), true);
		UsablesInRange.RemoveSingle(PotentialUsable);
	}
}

void UInteractionComponent::InitializeComponent()
{
	OnComponentBeginOverlap.AddDynamic(this, &UInteractionComponent::OnPotentialUsableCollisionEnter);
	OnComponentEndOverlap.AddDynamic(this, &UInteractionComponent::OnPotentialUsableCollisionEnd);
}


in .h i have


GENERATED_BODY()

	void OnPotentialUsableCollisionEnter(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
	void OnPotentialUsableCollisionEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

	virtual void InitializeComponent() override;

public:
	UPROPERTY(BlueprintReadWrite, Category = "Interaction Component")
		TArray<TScriptInterface<IIUsable>> UsablesInRange;

And im completly baffled by this error message
error C2664: ‘void FScriptInterface::SetObject(UObject *)’ : cannot convert argument 1 from ‘IIUsable *’ to ‘UObject *’
Can anyone shed some light on this?

It may be you need the array to be a pointer:



public:
    UPROPERTY(BlueprintReadWrite, Category="Interaction Component")
        TArray<TScriptInterface<IIUsable*>> UsablesInRange;


otherwise My Guess is your it is your UProperty. I’ve always had issues with Interfaces and actually until this post I did not know the TScriptInterface object existed. I would use a base object type and cast to my interface within the functions. So if the above does not work… try the following just to see.



public:
    UPROPERTY(BlueprintReadWrite, Category="Interaction Component")
        TArray<UObject> UsablesInRange;


Some more Documentation on using Interfaces would be nice as I myself have started some rather large AnswerHUB questions on the matter. C++ Interface in Blueprints

UPDATE:

Actually I’m almost sure it’s the pointer thing haha, looking at my own second bit of code it should be:



public:
    UPROPERTY(BlueprintReadWrite, Category="Interaction Component")
        TArray<UObject*> UsablesInRange;


UObject is a pointer in this one, so I am almost certain the first example should work. (And you taught me a new trick :slight_smile:

OR Actually it may be:



public:
    UPROPERTY(BlueprintReadWrite, Category="Interaction Component")
        TArray<TScriptInterface<IIUsable>*> UsablesInRange;


Pointer indicator After TScriptInterface<IIusable>… but I’d still try the first.

I know that can be done this way but it just seems… wrong :<

Also the



UPROPERTY(BlueprintReadWrite, Category="Interaction Component")
        TArray<TScriptInterface<IIUsable>*> UsablesInRange;

gives me
error : In InteractionComponent: Inappropriate ‘*’ on variable of type ‘TScriptInterface’, cannot have an exposed pointer to this type.

while



UPROPERTY(BlueprintReadWrite, Category = "Interaction Component")
		TArray<TScriptInterface<IIUsable*>> UsablesInRange;

gives me nice
error : In InteractionComponent: Missing ‘>’ in TScriptInterface

I don’t think it’s a pointer issue, your syntax looks right to me. However, ArcainOne is certainly correct in saying that there are some annoying limitations with interfaces in UE4 currently. There are a couple of things you could do, but I’m afraid all will probably seem ‘wrong’!

As ArcainOne says, you can just store an array of UObject pointers, which you know to implement the interface, and cast them when needed.

TScriptInterface I came across when attempting to expose a raw interface pointer as a parameter in a UFUNCTION. The compiler didn’t like it, but threw up some errors relating to TScriptInterface even though I hadn’t used it. It appears that you can achieve what I wanted by wrapping your interface in a TScriptInterface. However, as you’ve discovered, TScriptInterface appears to have the limitation that it can only be constructed from a UObject pointer. If you have a raw interface pointer instead, and do not know what the underlying UObject type is, you’re stuck.

In the code you gave, you should be able to work around this easily by just writing:


UsablesInRange.Add(OtherActor);
...
UsablesInRange.RemoveSingle(OtherActor);

The latter would require comparison on TScriptInterface to be implemented as expected, it would be worth checking that.

This should work for your given case, but you may in future find yourself faced with the same problem and not have access to the underlying object. A general workaround you can use for this is to always have a method in your interfaces as follows:


virtual UObject* AsUObject();

You then override this for every object which implements the interface and simply put ‘return this;’.

As you can see, using interfaces can get a bit ugly. Anyway I hope it helps.

I am greatly sadden to hear the other two options do not work… puts a new hitch in my dislike on how interfaces work in unreal but at the same time it changes nothing I am currently doing. I understand your feeling on why it “feels” wrong. But remember this, and it may be some help with that feeling, UObject is the absolute base object for anything in the game… so no matter what you build or do it is always a UObject. Secondly your array that keeps your list of UObjects should be protected or private which means the outside world must use an function to add to it which thus means NOTHING except IIUsable objects would EVER be in your array (as long as your function ensures it).

The other thing is this… C++ Interfaces and Blueprint Interfaces work… funny. the blueprint System does not know what an IIUsable “object” is and thus has NO definition or concept for an IIUsable Object. Which maybe why you cannot keep an array of IIUsable objects in a UProperty. However the blueprint system DOES know all the functions in your Interface. These functions are not “bound” to an object and appear almost like static functions (at least from my perspective in using them) in blueprints that take in any variables you have defined plus an additional “object” that these functions use to cast to the specified interface internally.

So basically if you plan on using this interface within blueprints you have to use UObject anyway because the blueprint system only knows your IIUsable functions, not your IIUsable object… at least I’ve never been able to do it… though now that I think about it… I’ve never tried adding “BlueprintType” to the UInterface macro… but that may not work.

Thanks for this thread. It helped me better understand what is going on with mixing interfaces in C++ and Blueprint. I wrote up a longer summary of what is happening and my theory on why at Grand unified C++/blueprint cast interface explanation - UI - Unreal Engine Forums which I thought readers of this thread might find useful.