Download

Victor's improved UseSystem

I made a few important changes to the Use system i made for the tutorial, now it works both in c++ and blueprints, and you can use blueprint interfaces to implement it, or just implement the IUsable interface in your c++ class. Both work.
Here you can see a video of how it works purely on blueprints
https://youtube.com/watch?v=flISoAMGqAQ

You can also implement the IUsable interface in a c++ class, giving you the OnUsed and OnFocus functions.

Im doing a c++ normal cast in the case the class has the IUsable interface, and then a blueprint style cast for the cases where the blueprint has the interface, but not the c++ class.

You can see the example code, using the FPS template, here https://github.com/vblanco20-1/Use-System
you are free to do whatever you want with this code.
**
How it works**

The most important part, is the Usable.h and Usable.cpp, if you see Usable.h, you can see this



#pragma once
#include "Usable.generated.h"

/**This interface has to be added to every Actor that can be used, you have to implement the OnUsed function */
UINTERFACE(MinimalAPI,Blueprintable)
class UUsable :public UInterface
{
	GENERATED_UINTERFACE_BODY()
	
};

class IUsable
{
	GENERATED_IINTERFACE_BODY()
	
	virtual void OnUsed(AController * user);

	virtual void  OnFocus(AController * user);

	// This will be called by the HUD if you want to display a name in the USE message, leave it empty if you dont want any message
	virtual FString GetNameToDisplay();

	//This event will be called when the character gets close to an object and presses the Use key.
	UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "On Used"))
	void BTOnUsed(AController * user);

	//This event will be called every frame if the object is being watched by the Use System in the HUD
	UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = " On Focus"))
	void  BTOnFocus( AController * user);
};
 

The UUsable is the UE4 interface, while the IUsable is the normal c++ interface, as you can see, i have the 2 functions and the 2 blueprint events there.
When you go to the cpp file, you see this




#include "MyProject.h"
#include "Usable.h"

UUsable::UUsable(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

//This is required for compiling, would also let you know if somehow you called
//the base event/function rather than the over-rided version
void IUsable::OnUsed(AController * user)
{
	BTOnUsed(user);
}

void IUsable::OnFocus(AController * user)
{	
	BTOnFocus(user);
}


FString IUsable::GetNameToDisplay()
{
	return FString("");
}


the 2 inteface functions call the blueprint events by default.
The character part is this



void AMyProjectCharacter::UseTarget()
{
	FHitResult HitTarget;
	TraceViewTarget(HitTarget);
	if (HitTarget.GetActor())
	{
		// Cast to IUsable for the C++ implementation of the interface
		IUsable* usable =Cast<IUsable>(HitTarget.GetActor());
		if (usable)
		{
			usable->OnUsed(GetController());
		}
		// pure blueprint interfaces wont be casted to IUsable, so we do it with the ImplementsInterface method and call the blueprint directly
		else if (HitTarget.GetActor()->GetClass()->ImplementsInterface(UUsable::StaticClass()))
		{
			IUsable::Execute_BTOnUsed(HitTarget.GetActor(), GetController());
		}
	}
}

void AMyProjectCharacter::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	// trace usable
	FHitResult HitTarget;
	TraceViewTarget(HitTarget);
	if (HitTarget.GetActor())
	{
		// Cast to IUsable for the C++ implementation of the interface
		IUsable* usable = Cast<IUsable>(HitTarget.GetActor());
		if (usable)
		{
			usable->OnFocus(GetController());
		}
		// pure blueprint interfaces wont be casted to IUsable, so we do it with the ImplementsInterface method and call the blueprint directly
		else if (HitTarget.GetActor()->GetClass()->ImplementsInterface(UUsable::StaticClass()))
		{
			IUsable::Execute_BTOnFocus(HitTarget.GetActor(), GetController());
		}
	}
}
void AMyProjectCharacter::TraceViewTarget(FHitResult &HitResult)
{

	// do a trace from view location, in the direction you are aiming, to get the object under the crosshair
	FCollisionQueryParams TraceParams("UseTrace", false, this);
	FVector TraceStart = GetPawnViewLocation();
	FVector TraceVector = GetBaseAimRotation().Vector();
	TraceVector.Normalize();
	FVector TraceEnd = TraceStart + (TraceVector * UseRange);
	HitResult = FHitResult(ForceInit);

	GetWorld()->LineTraceSingle(HitResult, TraceStart, TraceEnd, ECC_Visibility, TraceParams);
}


The TraceViewTarget does a trace from the camera and gives the hitresult, for use the functions. The function USeTarget is what calls the OnUsed functions on the Interface, and the Tick calls the OnFocus.
The important part is this:



               // Cast to IUsable for the C++ implementation of the interface
		IUsable* usable = Cast<IUsable>(HitTarget.GetActor());
		if (usable)
		{
			usable->OnFocus(GetController());
		}
		// pure blueprint interfaces wont be casted to IUsable, so we do it with the ImplementsInterface method and call the blueprint directly
		else if (HitTarget.GetActor()->GetClass()->ImplementsInterface(UUsable::StaticClass()))
		{
			IUsable::Execute_BTOnFocus(HitTarget.GetActor(), GetController());
		}


First, i do an InterfaceCast to do the normal c++ interface, but that does not get the blueprint interface, so it wont detect if the interface is implemented only on blueprint, so i check with ImplementsInterface, and then call the blueprint event directly, with Execute_BTOnFocus() functions, wich takes wich actor to execute the event, and the parameter of the event. This way this system works both in c++ and blueprints, without a problem.

Updated to 4.6

This looks interesting and I am going to try it out. It also looks like a nice alternative to Tom Looman’s UsableActor system, but I do would like to know where the major differences are? It looks like it’s easier to use as it’s implemented through a interface and not as Actor itself, am I right?

Greetz,
Dakraid

First, this is on c++, not only blueprints, and as an interface. Its power, is that you can just add the interface to whatever you want, both to blueprints, or to a c++ class, and it will work automatically. Making it quite flexible for a lot of things

Thanks for clearing that up.

I do encounter an issue though: within the TraceViewTarget function you used a variable called UseRange, the problem is that it’s nowhere declared (at least not on my end)?
Any ideas?

The complete line:



FVector TraceEnd = TraceStart + (TraceVector * UseRange);

Oh, that is a constant, you should add to the character. Anyway, im going to modify the code to add that Use Range float as a const variable in the TraceViewTarget function so its there.

Thank you! I also got it to work with my character now and it works fine so far!

Tell me if there is a bug/problem and ill fix it in the repo.