Core Concepts
Understanding how the OwnInteract system works under the hood.
Architecture
The system uses a component-based architecture with two main components:
Player / Character
└─ InteractionComponent (Detector)
↓ Detects & Communicates With
Interactable Object
├─ InteractableComponent (Receiver)
│ ├─ InteractionPoints[] (optional — multi-zone)
│ └─ InteractionOptions[] (optional — multi-choice)
└─ WidgetComponent (UI Display — auto-managed)
Two components, clear separation of concerns, fully event-driven. No base classes to inherit from — just add components to your existing Blueprints.
Interaction Flow
Complete lifecycle of a single interaction:
1. DETECTION
Player's InteractionComponent checks for objects every interval
└─ Uses selected Detection Method (Line / Sphere / Overlap / Cone)
└─ Only runs on locally controlled pawns (no server overhead)
2. FOCUS
Object found and passes all filters (tag, angle, distance, CanInteract)
├─ Highlight outline enabled on the object
├─ Widget becomes visible
└─ OnInteractableFocused event fired on the InteractionComponent
3. INPUT
Player presses interaction key
└─ StartInteraction() called
4. VALIDATION
System checks if interaction is allowed
├─ Is object enabled? (bIsEnabled)
├─ Not on cooldown? (bIsOnCooldown)
├─ Player in range? (server-side distance check)
└─ CanInteract() returns true?
5. EXECUTION
Events triggered based on Interaction Type
└─ Server events → gameplay logic
└─ Multicast events → visual feedback on all clients
6. UNFOCUS
Player looks away
├─ Highlight outline disabled
└─ Widget fades out and hides
Interaction Types
Instant
Behavior: Triggers immediately when input is pressed.
Use Cases: Open / close doors, pick up items, press buttons, activate switches
Events fired:
OnInteract(Server) — gameplay logicOnInteract_Multicast(All Clients) — visual/audio feedback
Event OnInteract (Server)
└─ Open Door
Event OnInteract_Multicast (All Clients)
└─ Play Sound / Particle Effect
Hold
Behavior: Player must hold input for a specified duration.
Use Cases: Lockpicking, hacking terminals, mining, arming a device
Settings:
HoldDuration— seconds to hold (e.g.,2.0)bReplicateHoldProgress— send progress to all clients
Events fired:
OnInteractionHoldStarted(Server) +_Multicast(All)OnInteractionHoldProgress(Local only) — 0.0–1.0 every frameOnInteractionHoldProgress_Multicast(All) — throttled, if enabledOnInteractionHoldCancelled(Server) +_Multicast(All)OnInteractionHoldCompleted(Server) +_Multicast(All)
Important: Use
OnInteractionHoldCompletedfor gameplay logic — Hold never firesOnInteract.
InstantAndHold
Behavior: Tap = Instant action. Hold past TapThreshold = Hold action.
Settings:
TapThreshold— e.g.,0.3secondsHoldDuration— e.g.,2.0seconds
Player presses key
├─ Released before TapThreshold? → Tap → OnInteract
└─ Held past TapThreshold? → Hold → OnHoldStarted, etc.
Tap/Hold decision is made locally on the client for zero latency, then confirmed to server via RPC.
Detection Methods
| Method | Description | Best For | Performance |
|---|---|---|---|
| Line Trace | Single ray from camera center | FPS, precision | Excellent |
| Sphere Trace | Swept sphere along ray | Third-person, controllers | Good |
| Overlap | Radius sphere around player | Adventure, proximity | Fair |
| Cone | Distance + angle combination | VR, wide-area scanning | Good |
Detection runs only on locally controlled pawns at DetectionInterval — not every frame, not on the server.
Filtering Systems
Tag Filtering
RequiredTags: ["Interactable"]
IgnoredTags: ["Locked"]
Angle Filtering
Only objects within camera’s field of view (MaxDetectionAngle).
Distance Filtering
Only objects within MinInteractionDistance – InteractionDistance.
CanInteract Filtering
Override in Blueprint to return false when conditions are not met (no key, quest not active, etc.).
When CanInteract() returns false:
bHideWidgetWhenUnavailable = true(default) → Widget hiddenbHideWidgetWhenUnavailable = false→ Widget shows in disabled state
Priority System
When multiple objects overlap, highest Priority wins.
Multi-Point Interactions
Multiple distinct interaction zones on a single object — each with its own InteractionData.
Use Cases:
- A car with separate doors, hood, trunk
- A control panel with individual buttons
- A safe with a dial and a handle
- A machine with a screen, lever, and power switch
Setup:
InteractableComponent:
└─ Interaction Points:
├─ [0] RelativeLocation: (0, -50, 0) | Name: "Open Driver Door" | Type: Instant
├─ [1] RelativeLocation: (0, 50, 0) | Name: "Open Passenger Door" | Type: Instant
└─ [2] RelativeLocation: (100, 0, 0) | Name: "Open Trunk" | Type: Hold | HoldDuration: 1.5
Each point has its own DetectionRadius — the player’s aim ray is checked against all active points, and the nearest one wins.
Runtime control:
// Disable a specific point (e.g., driver door already open)
Interactable Component → SetPointEnabled (PointIndex: 0, bEnabled: False)
Widget event:
Event OnInteractionPointFocused (PointData, PointIndex)
└─ Update widget to show this point's action name
Multi-Option Interactions
Multiple choices on a single interaction — the player scrolls through them before confirming.
Use Cases:
- Chest: “Take All” / “Inspect” / “Leave”
- NPC: “Talk” / “Trade” / “Follow Me”
- Item: “Equip” / “Examine” / “Drop”
- Terminal: “Hack” / “Shutdown” / “Reboot”
Setup:
InteractableComponent:
└─ Interaction Options:
├─ [0] Name: "Take All" | Type: Instant
├─ [1] Name: "Inspect" | Type: Instant
└─ [2] Name: "Leave" | Type: Instant
Input:
// Bind scroll wheel in Character Blueprint
Mouse Wheel Up → InteractionComponent → CycleInteractionOption (Direction: +1)
Mouse Wheel Down → InteractionComponent → CycleInteractionOption (Direction: -1)
Widget events:
Event OnInteractionOptionsAvailable (Options, ActiveIndex)
└─ Build option list UI (show all options, highlight active)
Event OnInteractionOptionChanged (ActiveOption, ActiveIndex)
└─ Update highlighted option
The active option’s InteractionData is used when the player presses the interact key.
Highlight System
When an object receives focus, the system automatically enables a custom depth stencil outline — the classic “interactable object glow” effect.
Setup — Post Process Material:
The highlight uses Unreal’s Custom Depth buffer. To see it, your Post Process Volume needs a material that reads CustomDepth and draws an outline for objects with a specific stencil value.
Configuration:
InteractableComponent:
├─ bEnableHighlight = True (default)
└─ HighlightStencilValue = 1 (0-255, match your PP material)
Runtime toggle:
Interactable Component → SetHighlightEnabled (False)
How it works:
- On focus → the plugin calls
SetRenderCustomDepth(true)+SetCustomDepthStencilValue()on the object’s mesh - On unfocus →
SetRenderCustomDepth(false) - Entirely automatic — no Blueprint wiring needed
Use different stencil values (e.g., 1 = blue, 2 = red) and a PP material that distinguishes them for colored outlines per interaction type.
Input Device Detection
The system automatically detects whether the player is using Keyboard/Mouse or Gamepad and notifies the widget so it can show the correct button hint.
How it works:
// In Character Blueprint, tell the component when input changes
InteractionComponent → SetActiveInputType (bIsGamepad: True)
// The widget receives this event automatically
Event OnInputDeviceChanged (bIsGamepad)
├─ True → Show "A" button icon
└─ False → Show "E" key icon
Widget function:
InteractionWidget → IsGamepadActive() → bool
Typical integration with Enhanced Input:
Event OnInputDeviceChanged (from Enhanced Input Subsystem)
└─ InteractionComponent → SetActiveInputType (bIsGamepad)
Widget System
Widgets are screen-space UI elements that always face the camera. The InteractableComponent manages lifecycle and space mode automatically.
Widget Events
| Event | When |
|---|---|
OnInteractionAvailable(InteractionData) |
Object focused |
OnInteractionUnavailable() |
Object unfocused |
OnInteractionTriggered() |
Instant triggered |
OnHoldStarted() |
Hold began |
OnHoldProgressUpdated(Progress) |
Progress 0.0–1.0 |
OnHoldCompleted() |
Hold succeeded |
OnHoldCancelled() |
Hold released early |
OnInteractionPointFocused(PointData, PointIndex) |
Multi-point: aim changed |
OnInteractionOptionsAvailable(Options, ActiveIndex) |
Multi-option: options shown |
OnInteractionOptionChanged(ActiveOption, ActiveIndex) |
Multi-option: scroll changed |
OnInputDeviceChanged(bIsGamepad) |
Keyboard/Gamepad switch |
Widget events are always fired locally on the owning client — never over the network.
Widget Unavailable State
bHideWidgetWhenUnavailable = True → Widget hidden when CanInteract() = false
bHideWidgetWhenUnavailable = False → Widget visible in disabled state
Multiplayer Architecture
Server Authority
1. Client presses "E" → StartInteraction()
2. ServerStartInteraction(Actor, PointIndex, OptionIndex) RPC sent
3. Server validates (distance, enabled, cooldown, CanInteract)
4. OnInteract fires (Server) + OnInteract_Multicast (All Clients)
Server vs Local Execution
bRequiresServerAuthority |
Behavior |
|---|---|
true (default) |
Server validates + executes, multicasts to clients |
false |
Executes immediately on local client, no RPC |
Event Authority Reference
| Event | Runs On |
|---|---|
OnInteract |
Server |
OnInteract_Multicast |
All Clients |
OnHoldStarted/Cancelled/Completed |
Server |
OnHold*_Multicast |
All Clients |
OnHoldProgress |
Local Client Only |
OnHoldProgress_Multicast |
All Clients (if bReplicateHoldProgress) |
| Widget Events | Always Local |
AI Support
Add InteractionComponent to an AI Character and set the target manually — no detection needed:
// AI Controller or Behavior Tree
InteractionComponent → SetInteractionTarget (TargetActor)
InteractionComponent → StartInteraction()
This bypasses the detection system entirely and directly starts an interaction with the specified actor.
Best Practices
Performance
| Do | Don’t |
|---|---|
DetectionInterval = 0.1 (default) |
Set below 0.05 |
| Use Tag Filtering | Detect everything and filter later |
Disable bShowDebug in shipping |
Ship with debug enabled |
InteractionComponent only on players / AI |
Add it to interactable objects |
Design
| Do | Don’t |
|---|---|
Clear InteractionName (“Open Door”) |
Generic labels (“E”) |
HoldDuration 1–3 seconds |
Over 5 seconds (frustrating) |
Use Priority for important objects |
Leave all at 0 |
OnInteract_Multicast for sounds/VFX |
Sounds only in server OnInteract |
| Different stencil values per object type | Same stencil for everything |
Common Patterns
Key-Required Door (CanInteract + disabled widget state)
Function CanInteract (Actor) → bool
└─ Return: Player HasItem "Key"
// bHideWidgetWhenUnavailable = false
Event OnInteractionAvailable
└─ CanInteract? True → "Open Door" / False → "Requires Key"
Multi-Zone Object (InteractionPoints)
InteractableComponent → Interaction Points:
├─ [0] "Enter Vehicle" — driver door position
└─ [1] "Open Trunk" — rear position
Loot Context Menu (InteractionOptions + Scroll)
InteractableComponent → Interaction Options:
├─ [0] "Take All" — Instant
├─ [1] "Inspect" — Instant
└─ [2] "Leave" — Instant
Character Input:
├─ Scroll Up → CycleInteractionOption(+1)
└─ Scroll Down → CycleInteractionOption(-1)
Colored Highlights per Type
Door: HighlightStencilValue = 1 → Blue outline (PP material)
Enemy: HighlightStencilValue = 2 → Red outline
Collectible: HighlightStencilValue = 3 → Yellow outline
Next Steps
- API Reference — Full property, event, and function reference
- Troubleshooting — Solutions to common problems
- FAQ — Frequently asked questions
Collision Channel {#collision-channel}
The plugin uses ECC_Visibility as its trace channel by default. This works out of the box
because most Static Mesh presets block Visibility.
Why you may want a dedicated channel
ECC_Visibility is shared with other engine systems (cameras, AI perception, foliage culling).
In complex projects this can cause unintended cross-system interference:
- An invisible blocker placed for AI sight lines blocks interaction traces too
- Meshes intentionally transparent to cameras become unexpectedly interactable
- It is harder to reason about which objects should or should not be detectable
How to set up a custom Interaction channel
- Project Settings → Engine → Collision → New Trace Channel
- Name:
Interaction - Default Response:
Ignore
- Name:
- Set the response on every interactable mesh to
Blockfor your new channel - In
InteractionComponentswap the trace channel inPerformLineTrace,PerformSphereTrace,PerformOverlap, andPerformConeDetectionfromECC_VisibilitytoECC_GameTraceChannel1(or whichever slot was assigned)
Note: This is an advanced customization. The default
ECC_Visibilitysetup is perfectly fine for most projects.