Download

Victor's Use System[Tutorial]

This is a complete copypaste from what i had in the UE4 beta program, Its a tutorial to create a USE system like the one in UDK, using interfaces. I will polish it a bit and upload to the wiki. But for now, enjoy it.
The system uses a IUsable interface, to check for objects that have that interface implemented, and if they have, you can use them.
Lets start with the IUsable interface itself:

Usable.h



#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)
class UUsable :public UInterface
{
	GENERATED_UINTERFACE_BODY()	
};

class IUsable
{
	GENERATED_IINTERFACE_BODY()
        // This function will be called when the user uses the object
	virtual void OnUsed(AController * user);
        // This function is called each frame from the hud, it should be used to put messages to the screen, like the USE promt in UDK
	virtual void DisplayPrompt(UCanvas * Canvas,AController * user);
};

Usable.cpp


   
    #include "Yourgame.h"
     
    //////////////////////////////////////////////////////////////////////////
    // ToStringInterface
     
    UUsable::UUsable(const class FPostConstructInitializeProperties& PCIP)
    : Super(PCIP)
    {
     
    }
     
    //This is required for compiling,  and its the base version, you can put something here and it will be the default behaviour
    void IUsable::OnUsed(AController * user)
    {
   
    }

    void IUsable::DisplayPrompt(UCanvas * Canvas,AController * user)
   {
   }


That was the IUSable interface, to implement it in an actor, you do like this


UCLASS()
    class AYourUsable: public AActor, public IUsable

in the class declaration, and then you implement the OnUsed and RenderHud methods in the cpp file of your usable actor

Im using the ShooterGame sample code as base.
Then, you have to make it be used by the rest of the code, so we add a variable to the character to hold the actor you are aiming(for hud), im calling it “UseFocus” here, and its an awful name, tell me if you think of a better name for it :smiley: .
in YourCharacter.h


IUsable * UseFocus;

Put it on Public, it will make things easier later.

Now, we add the detection code. This code will trace a line from the camera view of the character to the direction you are aiming, effectively picking the object you have under your crosshair.
On YourCharacter.cpp, at the bottom of the Tick() function. (this could also go into the controller if you want, but im using the ****)


if(Controller && Controller->IsLocalPlayerController()) // we check the controller becouse we dont want bots to grab the use object and we need a controller for the Getplayerviewpoint function
	{
		FVector CamLoc;
		FRotator CamRot;
	
		Controller->GetPlayerViewPoint(CamLoc, CamRot); // Get the camera position and rotation
		const FVector StartTrace = CamLoc; // trace start is the camera location
		const FVector Direction = CamRot.Vector();
		const FVector EndTrace = StartTrace + Direction *200; // and trace end is the camera location + an offset in the direction you are looking, the 200 is the distance at wich it checks
	
		// Perform trace to retrieve hit info
		FCollisionQueryParams TraceParams(FName(TEXT("WeaponTrace")),true,this);
		TraceParams.bTraceAsyncScene = true;
		TraceParams.bReturnPhysicalMaterial = true;

		FHitResult Hit(ForceInit);
		GetWorld()->LineTraceSingle(Hit, StartTrace, EndTrace, COLLISION_WEAPON, TraceParams); // simple trace function

		IUsable* usable = InterfaceCast<IUsable>(Hit.GetActor()); // we cast the hit actor to the IUsable interface
		if(usable) // we are looking to a usable object
		{
			UseFocus = usable; // as the actor under crosshairs is a usable actor, we store it for the hud.
		}
		else
		{
			UseFocus = NULL; // nothing, so we set the UseFocus pointer to NULL, so it wont give problems
		}
	}

I added another function to the character, in wich i implemented the Use feature, this will be called when you press the E key( remember to keybind this function or just call it from blueprint)



//YourCharacter.h Declaration
UFUNCTION(BlueprintCallable, Category=Hability) // i like to use blueprints instead of scripbinding it, so i made the Use function accesible from the blueprints
virtual void Use();

//YourCharacter.cpp Implementation
void AYourCharacter::Use()
{
        if(Controller == NULL) // we access the controller, make sure we have one, else we will crash
        {
              return;
        }
	FVector CamLoc;
	FRotator CamRot;
	Controller->GetPlayerViewPoint(CamLoc, CamRot);
	const FVector StartTrace = CamLoc;
	const FVector ShootDir =CamRot.Vector();
	const FVector EndTrace = StartTrace + ShootDir *200;
	
	// Perform trace to retrieve hit info
	FCollisionQueryParams TraceParams(FName(TEXT("WeaponTrace")),true,this);
	TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = true;

	FHitResult Hit(ForceInit);
	GetWorld()->LineTraceSingle(Hit, StartTrace, EndTrace, COLLISION_WEAPON, TraceParams);

	IUsable* pickup = InterfaceCast<IUsable>(Hit.GetActor()); 
	if(pickup) // we actually hit a picup
	{
		pickup->OnUsed(this->Controller); // call the interface so the object can do whatever it does when its used
	}
}


As you see, the Use function is more or less the same code as above for the Tick function.

The last part of the code, goes in the HUD, and its responsible for calling the DrawHUD function of the interface, so we draw prompts on the screen.

On the equivalent of ShooterHud.cpp in your project,add this to the function DrawHUD




AYourCharacter* My**** = Cast<AYourCharacter>(GetOwning****()); // grab the ****
if (My**** && My****->IsAlive())// check that is correct and alive, we dont want USE prompts when dead
{		
	if(My****->UseFocus != NULL)
	{
		My****->UseFocus->DisplayPrompt(Canvas,GetOwningPlayerController()); // call the DisplayPromt function so the Usable actor can draw itself
	}
}


And thats all. This system mostly mimics what UDK had for its USE feature, and once implemented, making new Usable actors is really easy, Just make them inherit from IUsable and implement their special functions.
I hope this explanation/code helped you, If you find problems, or want to note some kind of improvement, feel free to tell me, and ill answer questions or modify the code.

ADDITION: courtesy of djmidknight , who adds an appendix that lets this system to work with ShooterGame pickups, as they dont have normal collision, and dont block the use system traces by default. This steps are required if you want to add a volume that lets the system detect it.

  1. Open the existing pickup blueprint in ShooterGame or create a new blueprint
  2. In the Components tab under Components Category click Add Component and choose any of the Shapes(note this is a preference but I found sphere and capsule worked best)
  3. Name the Component Ie:Trigger or you can leave default name
  4. Select the Component scroll down to Shape and set it around 45 - 128 depending on how precise you want the pickup area to be
  5. Next scroll down to Collision
  6. Under Collision Presets choose Custom…
  7. Under Collision Enabled No Physics Collision
  8. Under Object type Pickup ( not sure if this will really change anything )
  9. Under Collision Responses Check the Ignore Box
  10. Under Trace Responses Check the Weapon Box under Block
  11. Last but not least Click Compile

Looks great solution, vblanco.
Works perfectly…

Suggestion:
I added a customizable distance of interaction

//YourCharacter.h Declaration
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=“Interaction”)
float PlayerInteractionDistance;

//YourCharacter.cpp Imprementation
Replace this line:
const FVector EndTrace = StartTrace + Direction *200;

For this:
const FVector EndTrace = StartTrace + Direction * PlayerInteractionDistance;

Thanks for sharing :slight_smile:

Update: Blueprint Support

A project needed the usable interface to work with blueprints, and so i investigated and learnt how to make it blueprintable.

To add blueprint events, add this to the IUsable class:



UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "On Used"))
	void BTOnUsed(AController * user);


	UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "Display Promt"))
    void  BTDisplayPrompt(UCanvas * Canvas, AController * user);


That will make BTOnUsed and BTDisplayPromtp blueprint events, so you can implement whatever logic you want in the blueprints.
also, in the UINTERFACE declaration on top of UUsable, add Blueprintable, so it should look like this:



UINTERFACE(MinimalAPI,Blueprintable)
class UUsable :public UInterface


If you dont put that, the interface wont appear in the blueprints.

Now that you have the events and the blueprintable interface. you need to call those events somewhere. So in the default implementation of On Used() and DisplayPromt functions, call the blueprint events. It should end like this on the Usable.cpp file.



void IUsable::OnUsed(AController * user)
{
	BTOnUsed(user);
}

void IUsable::DisplayPrompt(UCanvas * Canvas,AController * user)
{
	
	BTDisplayPrompt(Canvas, user);
}


And thats it, now you can implement the Usable interface into any blueprint actor you want, not needing to create a new actor class that has the interface implemented in C++.
Remember to call Super::OnUsed(user) and Super::DisplayPromt(Canvas,user) on your implementations of the IInterface in c++, else it wont call the blueprint events.

How about for someone who’s doing things in blueprints? Is there a way to do this completely in blueprints? Or is there a way to open to the code of my project as it is (using the blueprint 3rd person template)?

I’ve done this in Blueprints by deriving usable objects from a base class (which I named UsableActor) which respond to a ‘Player Use’ custom event.
The player Blueprint itself does a trace with a certain distance when your ‘Use’ key is pressed and if it hits something it tries to cast the hit object to a UsableActor, if it succeeds it will fire the ‘Player Use’ event on that object.

I can’t seem to get this last part to work. Unless I’m getting it wrong, Super:: can’t be called since the parent class of a Usable actor is AActor (or whatever we’re using). Someone could call IUsable::OnUsed but that would cause a loop and crash the game. Please correct me if I’m wrong. A complete usable actor example code would be great.

Other than that great tutorial, thanks!

I can’t seem to get this last part to work. Unless I’m getting it wrong, Super:: can’t be called since the parent class of a Usable actor is AActor (or whatever we’re using). Someone could call IUsable::OnUsed but that would cause a loop and crash the game. Please correct me if I’m wrong. A complete usable actor example code would be great.

Other than that great tutorial, thanks!