Skip to content

How to Setup Interaction

Dominik Pavlíček edited this page Apr 14, 2023 · 63 revisions
Table of contents
  1. Download the Plugin
    1. Marketplace
    2. GitHub
  2. Instal the Plugin
    1. Marketplace
    2. GitHub
      1. Game Folder
      2. Engine Folder
  3. Enable the Plugin
    1. Marketplace
    2. GitHub
  4. Open the Project
  5. Before you Start
    1. Collision Channels
      1. Config Files
      2. Project Settings
    2. Interaction Defaults
  6. Interactor Component
    1. Add Component
    2. Setup Component
      1. Custom Trace Start
  7. Interactable Component
    1. Prepare Actor
    2. Add Component
    3. Setup Component
      1. Interactable Data
      2. Widget Class
  8. Fix Issues
    1. Widget Size
    2. Fix Highlights
      1. Highlights through Player Pawn
    3. Fix Input

1. Download the Plugin

Marketplace

If you have already the plugin claimed, simply select the plugin and install it to the Engine version you are working with. Marketplace release always supports the last three major releases according to Epic Games policies.

If you don't see your Engine version listed on the Marketplace, you can always download the GitHub release.

GitHub release

If you feel experimental or simply need an older project to work with, the GitHub release page got you covered. All releases are listed HERE.

There are always two versions:

  • ActorInteractionPlugin
  • ActorInteractionPlugin_Binaries

The Binaries version skips the code build when opening the project and is recommended for Blueprint-based projects.


2. Instal the Plugin

Marketplace

Epic Games Launcher does the job for you, so you can continue to another chapter.

GitHub

With the GitHub release, there are two ways to install the plugin. Both have their advantages and disadvantages.

Game Folder

If you instal the plugin in Game Folder, this plugin will be available for this specific project only. If you are using the Blueprint project, it might require creating a dummy C++ class for packaging.

Installation to Game Folder requires you to drop the plugin into: .../ProjectFolder/Plugins

If you have no Plugins folder, simply create a new one.

Engine Folder

If you instal the plugin in Engine Folder, this plugin will be available to all projects using this Version! With Engine Folder you shouldn't need to create a dummy C++ class for packaging.

Installation to Engine Folder requires you to drop the plugin into: .../EngineFolder/EngineVersionFolder/Engine/Plugins/

Engine is usually installed in: C:/Users/{user}/UnrealEngine/{engine_version}


3. Enable the Plugin

Marketplace

If you are opening the project for the first time, you need to enable the plugin in Edit/Plugins/Mountea Framework

It will ask you to restart your Editor.

GitHub

If you are using the GitHub release, the plugin should be installed by default. If not, you need to enable the plugin in Edit/Plugins/Mountea Framework

It will ask you to restart your Editor.


4. Open the Project

If you are opening the project for the first time, you will be greeted by a Welcome Screen. This popup window shows:

  • If you open the project for the first time
  • If a new version is released

Welcome Screen contains useful links as well as full Changelog, so you can see what version with what features.

Welcome Screen requests those data from GitHub page, so if you have no access to the internet, this popup will not show any Changelog information ❗


5. Before you Start

Before you start creating any super complex interactions, there are a few steps that must be done. In order to make everything work, you should set up default values and collision channels. So let's start with those annoying configurations before so we can focus on interactions later.

Collision Channels

Actor Interaction Plugin can simply work out of the box with collision channels Engine contains by default, but it is much safer to use custom ones. Fear not, it might sound scary, but it is not at all! I have even prepared those collision channels for you!

Config Files

Open the {project_folder}/Config/DefaultEngine.ini file (works fine in Notepad, but I recommend to use Visual Studio Code).

Search for [/Script/Engine.CollisionProfile].

Once you find this part of the config file, all you have to do is to paste the following lines to the very end.

+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="InteractionTrace")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="InteractionOverlap")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel3,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="InteractionHover")

And you have done it!

Project Settings

If you want more user friendly approach, you can do it from the Engine interface. Go to Edit/Project Settings/Collision.

Once there, you have to manually create those three Collision Channels.

Object Channel

Object Channels are the following ones:

  • InteractionOverlap
  • InteractionHover

Set Default Response to Ignore.

Trace Channel

Object Channels are the following ones:

  • InteractionTrace

Set Default Response to Ignore.

Interaction Defaults

Interaction Defaults are a useful way to setup default values and have some safe backup if you accidentally break anything. Current implementation uses Defaults for all Components, in the future there are plans to add Presets, which will be then assignable to Components.

Let's open Edit/Project Settings/Actor Interaction Plugin settings and focus on variables we can set up here. Actor Interaction Plugin is located at the very bottom of the list, under the Mountea Framework category.

Editor

Enable Editor Debug

Globally enables/disables Editor Debug. If enabled, you can enable editor debug for each Component. If globally disabled, local settings are considered false.

Widget

Widget Update Frequency

Defines "Tick" frequency for widgets. Actor Interaction Plugin is not using Ticks for any component to keep as good as possible performance. In order to achieve smooth animations for UI, this Widget Update Frequency is used.

It is valued in Seconds, therefore lower the value, the more frequent the update is.

❗ 0.001 is lowest possible value you can set ❗

❗ Very low values might resolve in very poor performance ❗

Interactable Default Widget Class

Widget Blueprint Class which will be used as the Default one.

❗ Only classes which Implement the ActorInteractionWidget Interface are allowed ❗

Interaction Data

Interactable Default Data Table

Data Table reference which will be used as the default one.


6. Interactor

Once all the setup is done, we can finally start using the Interactions Components! And we should start with the Interactor Component, which is easier to set up and doesn't contain that many variables to fiddle with.

Interactor Component provides the active part of the Interaction process, let's imagine it as the player's eyes. Those can be of course assigned to NPCs as well, as this system is not limited to player input, which allows smart NPC behaviours. There are two master components:

  • Interactor Component: DEPRECATED, for legacy projects usage only
  • Interactor Component Base: The new system which is recommended to use

Add Interactor Component

For this scenario, I will use Third Person Example so everyone can follow those steps. Let's open the ThirdPersonCharacter blueprint. We all should see the same screen as this one.

The next step is to select the +Add Component button and search for Interactor. Actor Interactor Plugin comes with three C++ based classes, which are under the Interaction category and two Blueprint-based classes, which will be under the Custom category. Blueprint classes have BPC prefixes.

Blueprint classes provide the ability to override and extend C++ logic. By default, there is no extra functionality tied to Blueprint classes so it should not matter which one you choose. I will choose C++ class with this example.

You can choose from three options:

  • Interactor Component: DEPRECATED, please don't use
  • Interactor Component Trace: Basically a tracing laser from a specified location, either eyes or given one
  • Interacto Component Overlap: Passive component used to determine whether overlapping is with a collision of Interactable Component

For our example, I will choose Interactor Component Trace. After you select the Component from the +Add Component menu, you need to compile. You should see this screen.

Interactor Component Setup

As you can see, there are multiple categories under the Interaction detail tab. The most important ones are all located in the Required category.

To get the best results, let's select Collision Channel and pick Interaction Trace value we have created in the Collision Setup. This way your tracing won't affect any other channels.

Other options can be left as they are. If you are interested in how they work, each of them has an explanation tooltip and Wiki page. So your Interactor should be good to go as it is.

Use Custom Trace Location

If you don't like the default tracing settings (these are using Base Eye Height from the Actor details), you can update the Interactor to use Use Custom Start Transform, which will trace from a specified transform (including rotation!).

This option requires additional setup!

Scene Component

Easiest way to get the tracing Start is to add a new Scene Component, simpliest Component that can be moved around. That will act as root for the tracing. Attach that Scene component to the Mesh and position it roughly where eyes should be.

Now the trickiest part where the Tracing start is updated.

What happens here:

  • In Tick we control whether we are actually using the Custom Trace Start or not
  • If we do, we the call Set Custom Trace Start from the Interactor Component Trace
    • To the Trace Start we feed GetWorldTransform from newly created Scene component

If you feel super lazy, you can use this snipped and just feed the Interactor Component Trace and the Scene Component

Begin Object Class=/Script/BlueprintGraph.K2Node_Event Name="K2Node_Event_0"
   EventReference=(MemberParent=Class'"/Script/Engine.Actor"',MemberName="ReceiveTick")
   bOverrideFunction=True
   NodePosX=48
   NodePosY=-2304
   NodeGuid=ED0B698E4C5762D8B4BBB8A64D9883CE
   CustomProperties Pin (PinId=9404A42B46F720D555DEC4A18A51D701,PinName="OutputDelegate",Direction="EGPD_Output",PinType.PinCategory="delegate",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(MemberParent=Class'"/Script/Engine.Actor"',MemberName="ReceiveTick"),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=671410DD45AC0116467C669BE0129838,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,LinkedTo=(K2Node_IfThenElse_0 DAD080B341FC97ADCA77688048B79923,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=562A46FD470BAD6A10FFBEA794BAA017,PinName="DeltaSeconds",PinToolTip="Delta Seconds\nFloat",Direction="EGPD_Output",PinType.PinCategory="float",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="0.0",AutogeneratedDefaultValue="0.0",PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_1"
   bIsPureFunc=True
   bIsConstFunc=True
   FunctionReference=(MemberParent=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentTrace"',MemberName="GetUseCustomStartTransform")
   NodePosX=48
   NodePosY=-2192
   NodeGuid=5E73FBC24018F0A3AC1862A3E576A839
   CustomProperties Pin (PinId=ED58919B47445532074EF899E6C63A9F,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nInteractor Component Trace Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentTrace"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_3 AC2A3D24490DC4AC4CFF439408998AFC,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=1B739D7F484F06BF6670E88B482CF6FD,PinName="ReturnValue",PinToolTip="Return Value\nBoolean\n\nReturns whether using Custom Trace Transform.",Direction="EGPD_Output",PinType.PinCategory="bool",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="false",AutogeneratedDefaultValue="false",LinkedTo=(K2Node_IfThenElse_0 EFBCB0094CCFE58CD2EA08B179C5442E,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_IfThenElse Name="K2Node_IfThenElse_0"
   NodePosX=192
   NodePosY=-2304
   NodeGuid=7892A31E44AE63313A4EC6BAD609D91A
   CustomProperties Pin (PinId=DAD080B341FC97ADCA77688048B79923,PinName="execute",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_Event_0 671410DD45AC0116467C669BE0129838,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=EFBCB0094CCFE58CD2EA08B179C5442E,PinName="Condition",PinType.PinCategory="bool",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="true",AutogeneratedDefaultValue="true",LinkedTo=(K2Node_CallFunction_1 1B739D7F484F06BF6670E88B482CF6FD,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=DE8EA74A428B3452E4C8C5892FEE0E7E,PinName="then",PinFriendlyName=NSLOCTEXT("K2Node", "true", "true"),Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_3 70895A684A4167C0B672BC9274F423CF,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=9C10FD694B0187EB20C2FE91081BBF63,PinName="else",PinFriendlyName=NSLOCTEXT("K2Node", "false", "false"),Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_3"
   FunctionReference=(MemberParent=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentTrace"',MemberName="SetCustomTraceStart")
   NodePosX=400
   NodePosY=-2320
   NodeGuid=2190359C4FB230E8B4138BAF91D8C441
   CustomProperties Pin (PinId=70895A684A4167C0B672BC9274F423CF,PinName="execute",PinToolTip="\nExec",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_IfThenElse_0 DE8EA74A428B3452E4C8C5892FEE0E7E,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=F747C5C14D5BDB6EC329A5A45D44DC3B,PinName="then",PinToolTip="\nExec",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=F7F964A74FBF639543F2F18AB81FB041,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nInteractor Component Trace Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentTrace"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_1 AC2A3D24490DC4AC4CFF439408998AFC,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=D088397345E2E793521CD3B978479ED1,PinName="TraceStart",PinToolTip="Trace Start\nTransform\n\nValue to be used as Custom Trace Start.",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/CoreUObject.Transform"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_4 E112B1C44ABF02E13C74B9A7376B80D5,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_4"
   bIsPureFunc=True
   bIsConstFunc=True
   FunctionReference=(MemberParent=Class'"/Script/Engine.SceneComponent"',MemberName="K2_GetComponentToWorld")
   NodePosX=400
   NodePosY=-2128
   NodeGuid=9522267C4F471F9845D83798C6A9082B
   CustomProperties Pin (PinId=1E64587344EF174835A4CBB1A8DB0C70,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nScene Component Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/Engine.SceneComponent"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_2 46CD3E62469C1E021133ADACE89E1043,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=E112B1C44ABF02E13C74B9A7376B80D5,PinName="ReturnValue",PinToolTip="Return Value\nTransform\n\nGet the current component-to-world transform for this component",Direction="EGPD_Output",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/CoreUObject.Transform"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_3 D088397345E2E793521CD3B978479ED1,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object

❗ For futher optimization we strongly suggest to use Timers instead of Tick

Sockets

Sockets work the same way as Scene Components do, the only difference is that you request for the Socket Transform from the Mesh.


7. Interactable

Prepare the Actor

For this scenario, I will create a new Actor to show you the complete setup, however, this logic is translated to existing Actors as well.

Let's create a new Actor and call it BP_InterctableShowcaseActor.

Once the Actor is created, you should see a very similar screen to this one.

In order to have something to interact with, our Actor needs some Mesh! So let's add a simple Cube for this example (but if you want more interesting shapes, check out Unreal Bucket, they have amazing assets!) and work with this one.

Add Interactable Component

Once you have added the Static mesh, you can add Interactable the same way. +Add Component and select Interactable. Like with the Interactor, there are many options to pick from.

This is the same case we had with Interactor Components. 5 Blueprint classes and 6 C++ classes, where 1 class is DEPRECATED.

  • Interactable Component: DEPRECATED, do not use
  • Interactable Component Auto: Does automatically finishes interaction, no input is needed. Useful for Capture the Flag and similar gamemodes.
  • Interactable Component Hold: Requires input to be held for a specified duration, key E on a keyboard for 3 seconds, for instance.
  • Interactable Component Hover: WIP component which should be working with top down gamemodes and should only react to coursors.
  • Interactable Component Mash: Requires multiple inputs to be pressed within a specified time frame.
  • Interactable Component Press: Requires input to be pressed.

For our example, I will choose Interactable Component Hold. After you select the Component from the +Add Component menu, you need to compile. You should see this screen.

Set Transform

Similarly to Interactor Components there is Interaction Category with Subcategories where all variables are displayed. Interactable Components are different to Interactor Components, because Interactable Components have transforms, while Interactor Components are just attached to the Actor. Interactable Components, on the other hand, can and should be positioned where they belong.

To change the transform of the Interactable Component use the Gizmos. Once you move the Interactable a bit up, you can see that there is Billboard, which shows you where exactly the Component is. This Billboard is visible only in Editor.

Interactable Component Setup

Same as with Interactor Components, the most important ones are all located in the Required category in the Interaction category. And in the same manner you have setup the Interactor Trace Component, you should setup the Interactable Component. So update the Collision Channel to use InteractionTrace channel and compile.

Once done, there are two last things to do in the setup to make the interaction work. Those are:

  • Interactable Data
  • Widget Class

Let's go one after another.

Interactable Data

Interactable Data is a way to provide a modular approach for setup. All you need to do is to create Data Table (or preferably duplicate the one which comes with the Plugin) and fill that table with values. You can find Interactable Data under Optional category.

Widget Class

You might have noticed that Interactable Component has separated category User Interface. That is because the Interactable Component is a child class of Widget Component, which already provides this logic for us.

You are allowed to select any Widget Class you like, however, Validation will inform you if your Widget Class does not:

  • Implement ActorInteractionWidget Interface
  • Inherit from ActorInteractableWidget class

For our example, I have used WBP_InteractableActorWidget_Example2, which shows not just the slider, but values from the Interactable Data as well.


8. Fix Issues

Place Actor

To be able to do any interactions, you need to place your Interactable Actor to Level. I assume you know how to drag and drop actors from Content Browser to the Level. If not, join our Support Discord.

Widget size

As you can see, the widget in the world has very strange dimensions.

This can be easily fixed, however, keep in mind that this setting must be updated whenever you change the Widget class, as some are designed for different aspect ratios.

As you can see, the Widget now looks much better.

Fix Highlights

You might have noticed that our Interactable Acros is not highlighted. Don't worry, there is a simple fix for this.

4.26 - 5.0

If you are using Unreal Engine 4.26 to 5.0, you must follow following steps in order to get the highlight system work.

1. Project Settings

Open Edit/Project Settings/Rendering and set Custom Depth-Stencil Pass to Enabled with Stencil value. This enables engine to draw Custom Depth which is used for outline calculations.

2. PostProcess Volume

Once the Custom Depth is enabled, you need to make sure you are using that render pass. And that is achieved by using PostProcess Volume. That can be found in World Outliner tab or placed new from Place Actors tab.

Bounds

To be sure this effect works everywhere, make sure the PostProcess Volume is set to Unbound.

Materials

We need to stay in the PostProcess Volume Settings for a bit longer, now we need to enabled PostProcess Materials, which are being displayed in the viewport. Add new Material and select from Asset Reference as shown below.

Now all you need to do is to locate those materials to use. Actor Interaction Plugin comes with many examples for free, all of them are located here: ActorInteractionPlugin/Materials/PostProcessMaterials. You can choose any you like. If you don't see the plugin content, HERE you is how you enabled it.

If you feel extra lazy, you can simple copy the snippet below and paste in the empty refernce window.

(Weight=1.000000,Object=MaterialInstanceConstant'"/ActorInteractionPlugin/Materials/PostProcessMaterials/OutlineOverlayGlowing/MI_OutlineOverlayGlowing.MI_OutlineOverlayGlowing"')

In the end, you should see this settings.

Now you are good to go and try to play again and see the Cube being highlighted!

Fix glowing through Player

You have noticed that the Cube is being highlighted and glows even through the Player Pawn.

❗ This is not a bug, rather feature in Unreal Engine ❗

There is a simple way to fix this. Just select the Player, select its mesh and under Rendering category enabled Custom Depth pass like in the screenshot below.

5.1 and newer

If you are using Unreal Engine 5.1, you don't need to do anything! 5.1 version does support the older way of highlighting, however, does work very well with native highlights and overlay materials.

Fix Input

You might have noticed that you can see highlighted Interactable Actors, however, you have no way to pass down the input from your devices. Let's fix this.

Create Inputs

Open Edit/Project Settings/Input and Add new Action Mapping and select all keys you want to map here. I suggest to use simple name Interaction, but that is completely up to you. You don't have to save anything here.

❗ We strongly recommend to use the new Advanced Input System in newer Engine Versions ❗

Add Input to Player

Adding new Input in the Player class is very simple. Open the Player class you are using (in this example it is ThirdPersonCharacter) in the Event Graph:

  • Right click and find Interaction event we have created
  • Right click and find GetTimeSeconds function
  • Drag and drop the Interactor Component Trace we added earlier there
  • Drag a line from the Interactor Component Trace and search for Call On Interaction Key Pressed, then add the Call
  • Drag a line from the Interactor Component Trace and search for Call On Interaction Key Released, then add the Call
  • Connect Pressed from the Interaction event to the Call On Interaction Key Pressed, Released to the Call On Interaction Key Released
  • Connect Key from the Interaction event to both Call On Interaction Key Pressed and Call On Interaction Key Released
  • Connect ReturnValue from the GetTimeSeconds function to both Call On Interaction Key Pressed and Call On Interaction Key Released
  • Compile and save

If you feel super lazy, you can paste the code from the snippet below and just connect the Interactor Component Trace to both Call On Interaction Key Pressed and Call On Interaction Key Released

Begin Object Class=/Script/BlueprintGraph.K2Node_InputAction Name="K2Node_InputAction_0"
   InputActionName="Interaction"
   NodePosX=39
   NodePosY=-1904
   NodeGuid=5124E91B4A49CAF73AA8E6A3F8D28B41
   CustomProperties Pin (PinId=A4E37005449A80E73716B8A266EE1320,PinName="Pressed",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallDelegate_0 18104BE4466DBAD18F7E369431456FA8,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=C88CDD7540397617798CBC9F61FAB358,PinName="Released",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallDelegate_1 0D4AF8CB4153BB9C1ACC93992CB4C845,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=FEF0156D48E108F7A0BC2087F6338F42,PinName="Key",Direction="EGPD_Output",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/InputCore.Key"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="None",AutogeneratedDefaultValue="None",LinkedTo=(K2Node_CallDelegate_0 0E85A71F4F9B268C8CC7C8B66931FBA9,K2Node_CallDelegate_1 5ACF154643F638AABDD1D0A0E4C488B0,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallDelegate Name="K2Node_CallDelegate_0"
   DelegateReference=(MemberParent=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentBase"',MemberName="OnInteractionKeyPressed")
   NodePosX=352
   NodePosY=-1904
   NodeGuid=976F94F743C4C41031699CB44B7EFF4D
   CustomProperties Pin (PinId=18104BE4466DBAD18F7E369431456FA8,PinName="execute",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_InputAction_0 A4E37005449A80E73716B8A266EE1320,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=CE8EBCBC4ECE0D3ED0F6499B54B8D70F,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=179CE222498E47F64F8C4BA10A33F628,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "BaseMCDelegateSelfPinName", "Target"),PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentBase"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_0 596F392747AA98DE6E3A838352A0D6A9,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=7906A53A4EA06273EE30F6BAE173244C,PinName="TimeKeyPressed",PinType.PinCategory="float",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=True,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_0 B4C8D9B44ACC36ED30B7E093A4142C76,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=0E85A71F4F9B268C8CC7C8B66931FBA9,PinName="PressedKey",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/InputCore.Key"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=True,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="None",AutogeneratedDefaultValue="None",LinkedTo=(K2Node_InputAction_0 FEF0156D48E108F7A0BC2087F6338F42,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallDelegate Name="K2Node_CallDelegate_1"
   DelegateReference=(MemberParent=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentBase"',MemberName="OnInteractionKeyReleased")
   NodePosX=352
   NodePosY=-1728
   NodeGuid=36B672E34E90B5B580874F8BEABF6133
   CustomProperties Pin (PinId=0D4AF8CB4153BB9C1ACC93992CB4C845,PinName="execute",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_InputAction_0 C88CDD7540397617798CBC9F61FAB358,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=7E8A7B864F304D7D56C30686EF8845E0,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=309E36E346D501F5D4FF798E81243E09,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "BaseMCDelegateSelfPinName", "Target"),PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/ActorInteractionPlugin.ActorInteractorComponentBase"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_0 596F392747AA98DE6E3A838352A0D6A9,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=80CF8EC646F1E3C6C999C7818467EAB6,PinName="TimeKeyReleased",PinType.PinCategory="float",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=True,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_0 B4C8D9B44ACC36ED30B7E093A4142C76,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=5ACF154643F638AABDD1D0A0E4C488B0,PinName="ReleasedKey",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/InputCore.Key"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=True,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="None",AutogeneratedDefaultValue="None",LinkedTo=(K2Node_InputAction_0 FEF0156D48E108F7A0BC2087F6338F42,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_0"
   bIsPureFunc=True
   FunctionReference=(MemberParent=Class'"/Script/Engine.GameplayStatics"',MemberName="GetTimeSeconds")
   NodePosX=72
   NodePosY=-1680
   NodeGuid=B314F0EF430928583E4D95B0D33E88E1
   CustomProperties Pin (PinId=7DB332C143F08E2965783CA3BDAEDC97,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nGameplay Statics Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/Engine.GameplayStatics"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultObject="/Script/Engine.Default__GameplayStatics",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=3176CD354EA174A803CC848CF9761083,PinName="WorldContextObject",PinToolTip="World Context Object\nObject Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/CoreUObject.Object"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=B4C8D9B44ACC36ED30B7E093A4142C76,PinName="ReturnValue",PinToolTip="Return Value\nFloat\n\nReturns time in seconds since world was brought up for play, adjusted by time dilation and IS stopped when game pauses",Direction="EGPD_Output",PinType.PinCategory="float",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="0.0",AutogeneratedDefaultValue="0.0",LinkedTo=(K2Node_CallDelegate_0 7906A53A4EA06273EE30F6BAE173244C,K2Node_CallDelegate_1 80CF8EC646F1E3C6C999C7818467EAB6,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object

Now, you should be able to see the progress! I have switched Widget Class so it is easier to spot.


Plugin Content

If you can't see the plugin content, there is a simple way to enable it. In the Content Browser select View Options and enable Plugin Content.

Clone this wiki locally