add blueprints
This commit is contained in:
382
docs/blueprints/03-interaction/16_BPC_InteractionDetector.md
Normal file
382
docs/blueprints/03-interaction/16_BPC_InteractionDetector.md
Normal file
@@ -0,0 +1,382 @@
|
||||
# 16 — Interaction Detector (`BPC_InteractionDetector`)
|
||||
|
||||
## Purpose
|
||||
The player's "interaction eye" — performs trace-based detection of interactable objects in the world, sorts them by priority/distance, tracks the current best target, and manages the interaction prompt widget. Every interactive system in the game funnels through this component.
|
||||
|
||||
## Dependencies
|
||||
- **Requires:** `I_Interactable` (interface on all interactable actors), `PlayerCameraManager` (for trace origin), `BPC_MovementStateSystem` (block interaction during specific states)
|
||||
- **Required By:** `WBP_InteractionPrompt` (HUD element), `BPC_PickupComponent`, `BPC_InteractableDoorComponent`, `BPC_LeverPuzzleComponent`
|
||||
- **Engine/Plugin Requirements:** `LineTraceByChannel` (ECC_GameTraceChannel1 = Interaction), `TimerHandle` for scan interval
|
||||
|
||||
## Class Info
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Parent Class** | `ActorComponent` |
|
||||
| **Class Type** | Blueprint Component |
|
||||
| **Asset Path** | `Content/Framework/Interaction/BPC_InteractionDetector` |
|
||||
| **Implements Interfaces** | None |
|
||||
|
||||
---
|
||||
|
||||
## 1. Enums
|
||||
|
||||
### `E_InteractionInputMode`
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `Press = 0` | Single press to interact |
|
||||
| `Hold = 1` | Hold over duration to confirm |
|
||||
| `DoubleTap = 2` | Two rapid presses |
|
||||
| `Auto = 3` | Automatic on proximity (no input) |
|
||||
|
||||
### `E_InteractionPriority`
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `Low = 0` | Ambient / cosmetic items |
|
||||
| `Normal = 1` | Standard pickups, doors |
|
||||
| `High = 2` | Story-critical, puzzles |
|
||||
| `Emergency = 3` | Immediate threat (hide spot, weapon) |
|
||||
|
||||
### `E_DetectionState`
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `NoTarget = 0` | Nothing in range |
|
||||
| `TargetInRange = 1` | Potential target found |
|
||||
| `TargetConfirmed = 2` | Best target selected |
|
||||
| `Interacting = 3` | Currently performing interaction |
|
||||
|
||||
---
|
||||
|
||||
## 2. Structs
|
||||
|
||||
### `S_InteractableTarget`
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `TargetActor` | `AActor` | The interactable actor |
|
||||
| `InterfaceRef` | `I_Interactable` | Cast to interface |
|
||||
| `Priority` | `E_InteractionPriority` | Priority level |
|
||||
| `Distance` | `Float` | Distance from player to target |
|
||||
| `InteractionLabel` | `FText` | Display name (e.g. "Open Door", "Pick Up Key") |
|
||||
| `InputMode` | `E_InteractionInputMode` | How interaction is triggered |
|
||||
| `HoldDuration` | `Float` | Seconds required if InputMode is Hold |
|
||||
| `bIsHighlighted` | `Boolean` | Whether target is visually highlighted |
|
||||
| `TargetLocation` | `Vector` | World location for UI widget |
|
||||
|
||||
### `S_InteractionResult`
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `bSuccess` | `Boolean` | Whether interaction was successful |
|
||||
| `FailureReason` | `FText` | Human-readable failure reason |
|
||||
| `TargetActor` | `AActor` | The interacted actor |
|
||||
| `ContextTag` | `GameplayTag` | Tag for event recording |
|
||||
|
||||
---
|
||||
|
||||
## 3. Variables
|
||||
|
||||
### Configuration (Instance Editable, Expose On Spawn)
|
||||
|
||||
| Variable | Type | Default | Category | Description |
|
||||
|----------|------|---------|----------|-------------|
|
||||
| `InteractionRange` | `Float` | `250.0` | `Detection Config` | Max trace distance (cm) |
|
||||
| `DetectionAngle` | `Float` | `45.0` | `Detection Config` | Cone half-angle for detection (degrees) |
|
||||
| `TraceRadius` | `Float` | `10.0` | `Detection Config` | Sphere trace radius |
|
||||
| `ScanInterval` | `Float` | `0.1` | `Detection Config` | Seconds between detection scans |
|
||||
| `MaxTargetsInRange` | `Integer` | `16` | `Detection Config` | Max detected targets per scan |
|
||||
| `bShowDebugTrace` | `Boolean` | `false` | `Detection Config` | Visualise trace in editor |
|
||||
| `TraceChannel` | `TEnumAsByte<ECollisionChannel>` | `ECC_GameTraceChannel1` | `Detection Config` | Collision channel for interaction |
|
||||
| `bBlockDuringDeath` | `Boolean` | `true` | `Detection Config` | Block interaction while dead |
|
||||
| `bBlockDuringHiding` | `Boolean` | `true` | `Detection Config` | Block interaction while hidden |
|
||||
| `bBlockDuringCombat` | `Boolean` | `false` | `Detection Config` | Block interaction during combat |
|
||||
|
||||
### Internal (Private / Protected, No Expose)
|
||||
|
||||
| Variable | Type | Default | Category | Description |
|
||||
|----------|------|---------|----------|-------------|
|
||||
| `BestTargetIndex` | `Integer` | `-1` | `Detection State` | Index of currently selected target |
|
||||
| `DetectedTargets` | `Array<S_InteractableTarget>` | `[]` | `Detection State` | All detected targets this scan |
|
||||
| `CurrentTarget` | `S_InteractableTarget` | `-` | `Detection State` | Currently selected best target |
|
||||
| `DetectionState` | `E_DetectionState` | `NoTarget` | `Detection State` | Current state of the detector |
|
||||
| `bIsPerformingInteraction` | `Boolean` | `false` | `Detection State` | Whether interaction is in progress |
|
||||
| `HoldInteractionProgress` | `Float` | `0.0` | `Detection State` | Progress for hold-type interactions |
|
||||
| `OwnerPlayerController` | `APlayerController` | `None` | `Cache` | Cached player controller |
|
||||
| `OwnerCameraManager` | `APlayerCameraManager` | `None` | `Cache` | Cached camera manager |
|
||||
| `ScanTimerHandle` | `FTimerHandle` | `-` | `Timing` | Timer for scan interval |
|
||||
| `DetectedActors_LastFrame` | `Set<AActor>` | `{}` | `Tracking` | Previous frame targets for enter/exit detection |
|
||||
|
||||
### Replicated (if multiplayer)
|
||||
|
||||
| Variable | Type | Condition | Description |
|
||||
|----------|------|-----------|-------------|
|
||||
| `CurrentTarget` | `S_InteractableTarget` | `Replicated` | Synced selected target |
|
||||
|
||||
---
|
||||
|
||||
## 4. Functions
|
||||
|
||||
### Public Functions
|
||||
|
||||
#### `StartDetection` → `void`
|
||||
- **Description:** Begins the scan loop for interactable targets.
|
||||
- **Parameters:** None
|
||||
- **Flow:**
|
||||
1. Get owner Player Controller
|
||||
2. Get Player Camera Manager
|
||||
3. Start scan timer (ScanInterval)
|
||||
4. If bShowDebugTrace: enable debug line visualisation
|
||||
|
||||
#### `StopDetection` → `void`
|
||||
- **Description:** Stops the scan loop and clears detected targets.
|
||||
- **Parameters:** None
|
||||
- **Flow:**
|
||||
1. Clear scan timer
|
||||
2. Clear DetectedTargets array
|
||||
3. Set DetectionState = NoTarget
|
||||
4. Fire OnTargetLost
|
||||
5. Clear any highlight effects
|
||||
|
||||
#### `PerformInteraction` → `S_InteractionResult`
|
||||
- **Description:** Executes interaction on the current best target.
|
||||
- **Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `InputMode` | `E_InteractionInputMode` | How the input was triggered |
|
||||
- **Flow:**
|
||||
1. If not CurrentTarget valid or CurrentTarget actor is None: return failure
|
||||
2. If bIsPerformingInteraction: return failure (already interacting)
|
||||
3. If InputMode != CurrentTarget.InputMode: return failure (input mismatch)
|
||||
4. Set bIsPerformingInteraction = true
|
||||
5. Set DetectionState = Interacting
|
||||
6. Fire OnInteractionStarted
|
||||
7. Call CurrentTarget.InterfaceRef.ExecuteInteraction (owner)
|
||||
8. Wait for I_Interactable.OnInteractionCompleted or timeout
|
||||
9. On completion: set bIsPerformingInteraction = false
|
||||
10. Resume scanning
|
||||
11. Return S_InteractionResult with success/failure
|
||||
|
||||
#### `CancelInteraction` → `void`
|
||||
- **Description:** Aborts the current interaction if possible.
|
||||
- **Parameters:** None
|
||||
- **Flow:**
|
||||
1. If not bIsPerformingInteraction: return
|
||||
2. Call CurrentTarget.InterfaceRef.CancelInteraction
|
||||
3. Set bIsPerformingInteraction = false
|
||||
4. HoldInteractionProgress = 0.0
|
||||
5. Set DetectionState = TargetConfirmed
|
||||
6. Fire OnInteractionCancelled
|
||||
|
||||
#### `GetBestTarget` → `S_InteractableTarget`
|
||||
- **Description:** Returns the current best target.
|
||||
- **Parameters:** None
|
||||
- **Flow:** Return CurrentTarget
|
||||
|
||||
#### `HasTarget` → `Boolean`
|
||||
- **Parameters:** None
|
||||
- **Flow:** Return DetectionState >= TargetInRange
|
||||
|
||||
#### `ForceSetTarget` → `void`
|
||||
- **Description:** Forcefully sets a specific target (for scripted interactions).
|
||||
- **Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `TargetActor` | `AActor` | The specific actor to target |
|
||||
- **Flow:**
|
||||
1. If TargetActor implements I_Interactable:
|
||||
- Build S_InteractableTarget
|
||||
- Set CurrentTarget
|
||||
- Set DetectionState = TargetConfirmed
|
||||
- Fire OnTargetFound
|
||||
2. Else: fire OnInteractionError(not interactable)
|
||||
|
||||
### Private Functions
|
||||
|
||||
#### `ScanForInteractables (Timer)` → `void`
|
||||
- **Description:** Timer callback — performs trace and sorts targets.
|
||||
- **Flow:**
|
||||
1. If DetectionState == Interacting: return (skip scan while interacting)
|
||||
2. Get camera forward vector and world location
|
||||
3. Sphere trace forward (TraceRadius, InteractionRange, TraceChannel)
|
||||
4. For each hit actor:
|
||||
- If implements I_Interactable: add to DetectedTargets
|
||||
- If not: skip
|
||||
5. Remove duplicates by actor reference
|
||||
6. Sort by Priority (descending), then Distance (ascending)
|
||||
7. Clamp to MaxTargetsInRange
|
||||
8. Track enter/exit for each actor — fire OnTargetEntered / OnTargetExited
|
||||
9. Select BestTarget from sorted list
|
||||
10. Update DetectionState accordingly
|
||||
11. Fire OnTargetFound or OnTargetLost
|
||||
|
||||
#### `CalculateInteractionScore` → `Float`
|
||||
- **Description:** Computes a score for a target based on priority, distance, and facing angle.
|
||||
- **Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `Target` | `S_InteractableTarget` | The target to score |
|
||||
- **Flow:**
|
||||
1. Score = Priority * 100 - Distance * 0.5
|
||||
2. Facing bonus: if angle < 15 deg, add 50
|
||||
3. Return Max(0, Score)
|
||||
|
||||
#### `HighlightTarget` → `void`
|
||||
- **Description:** Applies highlight effect to target actor.
|
||||
- **Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `Target` | `S_InteractableTarget` | Target to highlight |
|
||||
| `bHighlighted` | `Boolean` | Whether to enable or disable |
|
||||
- **Flow:**
|
||||
1. Call Target.InterfaceRef.SetHighlighted(bHighlighted)
|
||||
|
||||
#### `GetViewTraceOrigin` → `Vector, Vector`
|
||||
- **Description:** Returns camera location and forward direction for trace.
|
||||
- **Parameters:** None
|
||||
- **Flow:**
|
||||
1. If OwnerCameraManager valid:
|
||||
- Return cam location and forward vector
|
||||
2. Else: fall back to owner actor location and forward
|
||||
|
||||
---
|
||||
|
||||
## 5. Event Dispatchers
|
||||
|
||||
| Dispatcher | Parameters | Bind Access | Description |
|
||||
|------------|-----------|-------------|-------------|
|
||||
| `OnTargetFound` | `S_InteractableTarget NewTarget` | `Public` | New best target selected |
|
||||
| `OnTargetLost` | `S_InteractableTarget LostTarget` | `Public` | Current target lost from view / range |
|
||||
| `OnTargetEntered` | `AActor TargetActor` | `Public` | Actor entered detectable range |
|
||||
| `OnTargetExited` | `AActor TargetActor` | `Public` | Actor left detectable range |
|
||||
| `OnInteractionStarted` | `S_InteractableTarget Target` | `Public` | Interaction began |
|
||||
| `OnInteractionCompleted` | `S_InteractionResult Result` | `Public` | Interaction finished |
|
||||
| `OnInteractionCancelled` | `S_InteractableTarget Target` | `Public` | Interaction was cancelled |
|
||||
| `OnInteractionError` | `FText ErrorMessage` | `Public` | Interaction blocked or failed |
|
||||
| `OnHoldProgressUpdated` | `Float Progress`, `S_InteractableTarget Target` | `Public` | Hold interaction progress [0..1] |
|
||||
|
||||
---
|
||||
|
||||
## 6. Overridden Events / Custom Events
|
||||
|
||||
### Event: `BeginPlay`
|
||||
- **Description:** Cache references, bind to relevant systems, start detection.
|
||||
- **Flow:**
|
||||
1. Get owning actor → ensure it is a Pawn
|
||||
2. Get Player Controller from owner
|
||||
3. Get Player Camera Manager from controller
|
||||
4. Bind to BPC_MovementStateSystem.OnPostureChanged — block when hidden
|
||||
5. Bind to BPC_HealthSystem.OnDeathStateChanged — block when dead
|
||||
6. StartDetection()
|
||||
|
||||
### Custom Event: `OnInputInteractPressed`
|
||||
- **Description:** Handles press input for interaction.
|
||||
- **Flow:**
|
||||
1. If DetectionState < TargetConfirmed: return
|
||||
2. If CurrentTarget.InputMode == Press:
|
||||
- PerformInteraction(Press)
|
||||
3. If CurrentTarget.InputMode == Hold:
|
||||
- Start hold timer
|
||||
4. If CurrentTarget.InputMode == DoubleTap:
|
||||
- Wait for second press within threshold
|
||||
|
||||
### Custom Event: `OnHoldProgressTick (Timer)` → `void`
|
||||
- **Description:** Ticks hold interaction progress and fires progress dispatcher.
|
||||
- **Flow:**
|
||||
1. HoldInteractionProgress += DeltaTime / CurrentTarget.HoldDuration
|
||||
2. Clamp to 1.0
|
||||
3. Fire OnHoldProgressUpdated
|
||||
4. If HoldInteractionProgress >= 1.0: PerformInteraction(Hold)
|
||||
|
||||
### Custom Event: `OnInputInteractReleased`
|
||||
- **Description:** Cancels hold interaction if button released early.
|
||||
- **Flow:**
|
||||
1. If CurrentTarget.InputMode == Hold and not completed:
|
||||
- CancelInteraction()
|
||||
- HoldInteractionProgress = 0.0
|
||||
|
||||
---
|
||||
|
||||
## 7. Blueprint Graph Logic Flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Scan Timer Fires] --> B[Get Camera Location / Forward]
|
||||
B --> C[SphereTraceForObjects]
|
||||
C --> D[Hit actors found?]
|
||||
D -->|No| E[Clear targets]
|
||||
E --> F[DetectionState = NoTarget]
|
||||
F --> G[Fire OnTargetLost]
|
||||
|
||||
D -->|Yes| H[Filter by I_Interactable]
|
||||
H --> I[Sort by Priority then Distance]
|
||||
I --> J[Select BestTarget]
|
||||
J --> K{BestTarget changed?}
|
||||
K -->|Yes| L[Unhighlight old target]
|
||||
L --> M[Highlight new target]
|
||||
M --> N[Fire OnTargetFound]
|
||||
K -->|No| O[Keep current target]
|
||||
|
||||
P[OnInputInteractPressed] --> Q{DetectionState >= Confirmed?}
|
||||
Q -->|No| R[Return]
|
||||
Q -->|Yes| S{InputMode match?}
|
||||
S -->|Press| T[PerformInteraction]
|
||||
S -->|Hold| U[Start hold timer]
|
||||
S -->|DoubleTap| V[Start double-tap timer]
|
||||
T --> W[Call ExecuteInteraction on target]
|
||||
W --> X[Fire OnInteractionStarted]
|
||||
X --> Y{Interaction succeeded?}
|
||||
Y -->|Yes| Z[Fire OnInteractionCompleted]
|
||||
Y -->|No| AA[Fire OnInteractionError]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Communication Matrix
|
||||
|
||||
| Who Talks | How | What Is Sent |
|
||||
|-----------|-----|-------------|
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnTargetFound` -> `WBP_InteractionPrompt` (show prompt) |
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnTargetLost` -> `WBP_InteractionPrompt` (hide prompt) |
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnInteractionStarted` -> `BPC_PlayerMetricsTracker` (log event) |
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnInteractionCompleted` -> `BPC_PlayerMetricsTracker` (log result) |
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnHoldProgressUpdated` -> `WBP_InteractionPrompt` (progress bar) |
|
||||
| `BPC_InteractionDetector` | `Dispatcher` | `OnInteractionCancelled` -> `WBP_InteractionPrompt` (hide) |
|
||||
| `BPC_InteractionDetector` | `Listener` | Binds to `BPC_MovementStateSystem.OnPostureChanged` |
|
||||
| `BPC_InteractionDetector` | `Listener` | Binds to `BPC_HealthSystem.OnDeathStateChanged` |
|
||||
| `BPC_InteractionDetector` | `Direct` | Calls `I_Interactable.ExecuteInteraction` on target |
|
||||
| `BPC_InteractionDetector` | `Direct` | Calls `I_Interactable.CancelInteraction` on target |
|
||||
| `BPC_InteractionDetector` | `Direct` | Calls `I_Interactable.SetHighlighted` on target |
|
||||
| `BPC_InteractionDetector` | `Direct call (other)` | `GetBestTarget` called by `WBP_InteractionPrompt` for name |
|
||||
| `PC_PlayerController` | `Input Event` | Binds press / release / hold to `OnInputInteractPressed` etc. |
|
||||
|
||||
---
|
||||
|
||||
## 9. Validation / Testing Checklist
|
||||
|
||||
- [ ] Trace detects actors implementing I_Interactable at correct range
|
||||
- [ ] Priority sorting: Emergency targets always selected over Low
|
||||
- [ ] Same priority: closest target selected
|
||||
- [ ] Detection respects blocking states (dead, hiding)
|
||||
- [ ] Hold interaction progress updates and fires progress dispatcher
|
||||
- [ ] Double-tap interaction waits for second press within window
|
||||
- [ ] Cancelling hold interaction resets progress and fires cancelled
|
||||
- [ ] Interaction blocked during combat if bBlockDuringCombat is true
|
||||
- [ ] Targeting auto-switches if closer target enters range
|
||||
- [ ] Target exit detection fires when actor moves beyond max range
|
||||
- [ ] Edge case: No targets in range — DetectionState stays NoTarget
|
||||
- [ ] Edge case: Target destroyed mid-interaction — cancels gracefully
|
||||
- [ ] Edge case: Multiple interactables in trace — selects correctly
|
||||
- [ ] Debug trace visualisation draws correct sphere/line
|
||||
- [ ] Scan timer pauses while interacting, resumes after completion
|
||||
|
||||
---
|
||||
|
||||
## 10. Reuse Notes
|
||||
|
||||
- TraceChannel should be set to a custom object channel (ECC_GameTraceChannel1) with only interactable actors responding.
|
||||
- Priority values can be overridden per actor via the `I_Interactable` interface's `GetInteractionPriority` function.
|
||||
- The hold interaction progress is designed to drive a radial progress widget in the HUD.
|
||||
- For controller/console: `E_InteractionInputMode.Hold` is preferred to prevent accidental interactions.
|
||||
- The same component can be attached to NPCs if they need interaction detection.
|
||||
- To support networked games: replicate CurrentTarget and have each client run their own trace locally.
|
||||
|
||||
---
|
||||
|
||||
*Blueprint Spec: Interaction Detector. Conforms to TEMPLATE.md v1.0 — part of the UE5 Modular Game Framework.*
|
||||
Reference in New Issue
Block a user