- Added BPC_PlatformServiceAbstraction to centralize platform detection and SDK routing for achievements, cloud saves, and overlays. - Updated dependencies across various systems to utilize the new platform service for consistent platform handling. - Deprecated old platform enums in favor of a unified EPlatformFamily enum. - Enhanced documentation for affected systems to reflect changes in platform handling and dependencies.
27 KiB
148 — Haptics Controller (BPC_HapticsController)
Blueprint-Only Implementation — UE 5.5–5.7 fully supports controller haptics/force feedback from Blueprints. No C++ required. This component wraps UE5's
Play Force Feedback,Set Haptics By Value, and DualSense adaptive trigger APIs behind a GameplayTag-driven event system.
Purpose
Abstraction layer for all controller haptic feedback and force feedback effects. Gameplay systems trigger haptics by GameplayTag (e.g., Haptic.Damage.Heavy) rather than calling raw UE5 haptic APIs. This component handles platform detection (Xbox rumble vs PS5 DualSense adaptive triggers vs generic PC gamepad), respects accessibility settings (BPC_AccessibilitySettings.bHapticsEnabled), and manages effect priority/conflict resolution.
Dependencies
- Requires:
DA_HapticProfile(effect definitions),BPC_AccessibilitySettings(master toggle),BPC_StateManager(heart rate for heartbeat haptic),BPC_PlatformServiceAbstraction(platform detection — replaces own platform enum) - Required By:
BPC_HealthSystem(damage haptics),BPC_FirearmSystem(weapon fire kick),BPC_MeleeSystem(melee impact),BPC_PhysicsDragSystem(grab/release),BPC_ScareEventSystem(tension rumble),BP_ItemPickup(pickup pulse),BPC_MovementStateSystem(footstep rumble via GASP notifies) - Engine/Plugin Requirements: Enhanced Input Plugin (controller detection), PlayStation 5 Controller Plugin (DualSense adaptive triggers — optional, graceful fallback)
Class Info
| Property | Value |
|---|---|
| Parent Class | ActorComponent |
| Class Type | Blueprint Component |
| Asset Path | Content/Framework/Settings/BPC_HapticsController |
| Implements Interfaces | None |
| Attachment | Player Controller (PC_CoreController) |
1. Enums
EHapticEvent
| Value | Description |
|---|---|
None = 0 |
No haptic effect |
Damage = 1 |
Player takes damage (intensity scales with amount) |
HeavyDamage = 2 |
Critical/major damage hit |
Heartbeat = 3 |
Heartbeat pulse (tempo from BPC_StateManager heart rate) |
WeaponFire = 4 |
Weapon fire kick |
WeaponReload = 5 |
Reload action feedback |
MeleeImpact = 6 |
Melee weapon hit/kill |
Footstep = 7 |
Footstep surface-dependent rumble |
Explosion = 8 |
Nearby explosion or environmental blast |
PickupItem = 9 |
Item picked up |
DropItem = 10 |
Item dropped/discarded |
GrabObject = 11 |
Physics object grabbed |
ReleaseObject = 12 |
Physics object released/thrown |
ScareEvent = 13 |
Jump scare / tension event |
AmbientPulse = 14 |
Low-level ambient tension rumble |
UI_Confirm = 15 |
Menu confirm/select haptic click |
UI_Navigate = 16 |
Menu navigation tick |
LowHealth = 17 |
Health-critical warning pulse |
StaminaExhausted = 18 |
Stamina depleted heavy pulse |
Death = 19 |
Player death rumble |
EHapticMotor
| Value | Description |
|---|---|
Left = 0 |
Left (low-frequency) motor only |
Right = 1 |
Right (high-frequency) motor only |
Both = 2 |
Both motors simultaneously |
EControllerPlatform (deprecated — use EPlatformFamily from BPC_PlatformServiceAbstraction. This enum is mapped internally from the unified platform enum.)
| Value | Description |
|---|---|
Unknown = 0 |
Platform not yet detected |
PC_Generic = 1 |
PC with generic gamepad (XInput) |
Xbox = 2 |
Xbox Series X|S / Xbox One controller |
PS5_DualSense = 3 |
PlayStation 5 DualSense controller |
PS4_DualShock = 4 |
PlayStation 4 DualShock 4 controller |
2. Structs
S_HapticRequest
| Field | Type | Description |
|---|---|---|
ProfileTag |
FGameplayTag |
Which DA_HapticProfile to use |
EventType |
EHapticEvent |
Event category |
IntensityMultiplier |
Float |
Scale intensity (0.0–2.0, 1.0 = default) |
DurationOverride |
Float |
Override duration (-1 = use profile default) |
Priority |
Int32 |
Higher interrupts lower (0–100) |
RequestTime |
Float |
Game time when requested (for cooldown) |
3. Variables
Configuration (Instance Editable)
| Variable | Type | Default | Category | Description |
|---|---|---|---|---|
HapticProfileMap |
TMap<FGameplayTag, DA_HapticProfile> |
Empty |
Config |
All haptic profiles loaded at startup |
bHapticsEnabled |
Bool |
true |
Config |
Master toggle (synced from BPC_AccessibilitySettings) |
bEnableDualSenseTriggers |
Bool |
true |
Config |
Enable adaptive trigger effects on PS5 |
bEnableSpeakerAudio |
Bool |
true |
Config |
Enable controller speaker audio on PS5 |
MinTimeBetweenEffects |
Float |
0.05 |
Config |
Minimum seconds between any two effects (prevents rumble spam) |
HapticIntensityScale |
Float |
1.0 |
Config |
Global intensity multiplier (0.0 = off, 1.0 = full) |
HeartbeatMinBPM |
Float |
40.0 |
Config |
Minimum BPM for heartbeat haptic |
HeartbeatMaxBPM |
Float |
180.0 |
Config |
Maximum BPM for heartbeat haptic |
Internal (Private)
| Variable | Type | Default | Category | Description |
|---|---|---|---|---|
CurrentPlatform |
EControllerPlatform |
Unknown |
State |
Detected controller platform |
bIsInitialized |
Bool |
false |
State |
Whether Initialize has completed |
CachedPlayerController |
APlayerController |
None |
Cache |
Cached owner PlayerController reference |
ActiveHapticEffect |
UForceFeedbackEffect |
None |
State |
Currently playing effect asset |
LastPlayTime |
Float |
0.0 |
State |
Game time of last played effect |
PendingRequest |
S_HapticRequest |
Empty |
State |
Currently queued request |
bHeartbeatActive |
Bool |
false |
State |
Whether heartbeat loop is active |
4. Functions
Public Functions
Initialize → void
- Description: Detects controller platform, loads all
DA_HapticProfileinstances intoHapticProfileMap, caches PlayerController. - Parameters: None
- Blueprint Authority: Local Client Only
- Flow:
- Get Owner → Cast to
APlayerController→ Store asCachedPlayerController - Detect platform: Check
UGameplayStatics::GetPlatformName()+ connected input devices - Set
CurrentPlatform(Xbox, PS5_DualSense, PS4_DualShock, or PC_Generic) - Load all
DA_HapticProfileassets fromContent/Framework/DataAssets/Haptics/intoHapticProfileMap - If
BPC_AccessibilitySettingsexists on owner → bind toOnHapticsToggleChanged - Bind to
BPC_StateManager.OnHeartRateChangedfor heartbeat haptic - Set
bIsInitialized = true - Broadcast
OnHapticsControllerInitialized
- Get Owner → Cast to
PlayHapticByTag → void
- Description: Play a haptic effect by its GameplayTag. Main entry point for all gameplay systems.
- Parameters:
Param Type Description ProfileTagFGameplayTagTag matching a DA_HapticProfile IntensityMultiplierFloatScale intensity (default 1.0) - Blueprint Authority: Local Client Only
- Flow:
- Validate
bHapticsEnabledandbIsInitialized— if disabled, return - Check
MinTimeBetweenEffectscooldown — if too soon, queue or skip - Look up
DA_HapticProfilefromHapticProfileMapbyProfileTag - If not found: log warning, return
- Build
S_HapticRequestwith profile data - Call
PlayHapticInternal()with the request - Broadcast
OnHapticPlayedwith tag
- Validate
PlayHapticByEvent → void
- Description: Play a haptic effect by event type. Convenience wrapper for systems that don't know the exact tag.
- Parameters:
Param Type Description EventTypeEHapticEventWhich event to trigger IntensityMultiplierFloatScale intensity (default 1.0) - Flow: Converts
EHapticEventto default tag (e.g.,Damage→Haptic.Damage.Default) and callsPlayHapticByTag.
StopHaptic → void
- Description: Stop all currently playing haptic effects.
- Flow:
- If
CachedPlayerControllervalid: callStop Force Feedbacknode - Set
ActiveHapticEffect = None - If
bHeartbeatActive: callStopHeartbeatHaptic() - Broadcast
OnHapticStopped
- If
PlayHeartbeatHaptic → void
- Description: Start or update the continuous heartbeat pulse haptic at the given BPM.
- Parameters:
Param Type Description BeatsPerMinuteFloatHeart rate in BPM (from BPC_StateManager) - Flow:
- Clamp BPM to
HeartbeatMinBPM—HeartbeatMaxBPM - Calculate pulse interval:
Interval = 60.0 / BPM - Set
bHeartbeatActive = true - Start a looping timer at
Intervalseconds - Each tick: call
PlayHapticByTag(Haptic.Heartbeat)with intensity from BPM - If BPM changes: update timer interval
- Clamp BPM to
StopHeartbeatHaptic → void
- Description: Stop the continuous heartbeat haptic loop.
- Flow: Clear heartbeat timer, set
bHeartbeatActive = false.
SetHapticsEnabled → void
- Description: Enable or disable all haptic output. Called by accessibility toggle.
- Parameters:
Param Type Description bEnabledBoolNew state - Flow:
- Set
bHapticsEnabled = bEnabled - If disabled: call
StopHaptic() - Broadcast
OnHapticsEnabledChanged
- Set
SetControllerPlatform → void
- Description: Force a specific controller platform (for testing or hot-swap).
- Parameters:
Param Type Description PlatformEControllerPlatformTarget platform
GetControllerPlatform → EControllerPlatform
- Description: Returns the detected controller platform. Read-only.
IsDualSenseConnected → Bool
- Description: Returns true if a PS5 DualSense controller is detected.
- Flow: Returns
CurrentPlatform == PS5_DualSense
SetDualSenseTriggerEffect → void
- Description: Set adaptive trigger resistance on a specific DualSense trigger. No-op on non-DualSense platforms.
- Parameters:
Param Type Description TriggerSideName"Left" or "Right" EffectTypeName"Resistance", "Vibration", "WeaponFire", "BowDraw", etc. StartPositionInt32Trigger position where effect begins (0–9) StrengthInt32Effect strength (0–8) - Blueprint Authority: Local Client Only
- Flow:
- If
CurrentPlatform != PS5_DualSense: return (graceful no-op) - If
bEnableDualSenseTriggers == false: return - Call platform-specific DualSense trigger API via
PlayerController - Log effect for debugging
- If
Protected / Private Functions
PlayHapticInternal → void
- Description: Core haptic playback logic. Resolves platform, selects the right effect asset, handles priority conflicts.
- Parameters:
Param Type Description RequestS_HapticRequestFull haptic request - Flow:
- Check priority: if
Request.Priority < PendingRequest.PriorityandPendingRequestis active → skip - If
Request.Priority >= PendingRequest.Priority: interrupt current effect - Resolve platform: select
UForceFeedbackEffectfromDA_HapticProfileforCurrentPlatform - If no platform-specific asset: fall back to generic PC effect
- Apply
IntensityMultipliertoHapticIntensityScale - Call
Play Force Feedbacknode onCachedPlayerController:- Input:
ForceFeedbackEffect,IntensityMultiplier,bLooping=false,bIgnoreTimeDilation=true
- Input:
- Store as
ActiveHapticEffect - Set
LastPlayTime = GameTimeInSeconds - Broadcast
OnHapticPlayed
- Check priority: if
DetectControllerPlatform → void
- Description: Queries the input system to determine which controller is connected.
- Flow:
- Check
UGameplayStatics::GetPlatformName() - If platform contains "PS5" →
PS5_DualSense - If platform contains "PS4" →
PS4_DualShock - If platform contains "Xbox" or "XboxOne" or "XSX" →
Xbox - Otherwise: check connected devices → if gamepad found →
PC_Generic, else →Unknown
- Check
5. Event Dispatchers
| Dispatcher | Parameters | Bind Access | Description |
|---|---|---|---|
OnHapticsControllerInitialized |
— | Public |
Fired after Initialize completes |
OnHapticPlayed |
FGameplayTag ProfileTag, EHapticEvent EventType, Float Intensity |
Public |
Fired when any haptic effect starts |
OnHapticStopped |
— | Public |
Fired when haptics stop (manual or effect ends) |
OnHapticsEnabledChanged |
Bool bEnabled |
Public |
Fired when master toggle changes |
OnControllerPlatformChanged |
EControllerPlatform NewPlatform |
Public |
Fired on controller hot-swap |
OnDualSenseTriggerActivated |
Name TriggerSide, Name EffectType |
Public |
Fired when adaptive trigger effect applied (PS5 only) |
6. Overridden Events / Custom Events
Event: BeginPlay
- Description: Startup. Calls
Initialize(). - Flow:
- Call
Initialize() - If
CachedPlayerControlleris null: log error, return - Register for controller connection/disconnection events
- Call
Event: EndPlay
- Description: Cleanup on component destruction.
- Flow:
- Call
StopHaptic()(stop all effects) - Call
StopHeartbeatHaptic() - Unbind from all dispatchers
- Clear cached references
- Call
7. Blueprint Graph Logic Flow
flowchart TD
A[BeginPlay] --> B[Initialize]
B --> C{Detect Controller Platform}
C --> D[Set CurrentPlatform]
D --> E[Load DA_HapticProfile Map]
E --> F[Bind to AccessibilitySettings.OnHapticsToggleChanged]
F --> G[Bind to StateManager.OnHeartRateChanged]
G --> H[Broadcast OnInitialized]
I[PlayHapticByTag] --> J{bHapticsEnabled?}
J -->|No| K[Return]
J -->|Yes| L{Cooldown check}
L -->|TooSoon| M[Queue or skip]
L -->|OK| N[Lookup DA_HapticProfile]
N --> O{Found?}
O -->|No| P[Log Warning]
O -->|Yes| Q[Build S_HapticRequest]
Q --> R[PlayHapticInternal]
R --> S{Platform == PS5?}
S -->|Yes| T[Play Force Feedback PS5 Profile]
S -->|No| U[Play Force Feedback Generic]
T --> V[Broadcast OnHapticPlayed]
U --> V
W[PlayHeartbeatHaptic] --> X[Clamp BPM]
X --> Y[Calculate Interval = 60/BPM]
Y --> Z[Start Looping Timer]
Z --> AA[Each Tick: PlayHapticByTag Haptic.Heartbeat]
8. Communication Matrix
| Who Talks | How | What Is Sent |
|---|---|---|
BPC_HealthSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.Damage.Heavy, Intensity) on damage taken |
BPC_FirearmSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.WeaponFire.Pistol) on fire |
BPC_MeleeSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.MeleeImpact) on hit |
BPC_PhysicsDragSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.Grab) / Haptic.Release |
BPC_ScareEventSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.ScareEvent) on scare trigger |
BPC_ReloadSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.WeaponReload) on reload complete |
BP_ItemPickup |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.PickupItem) on collect |
BPC_MovementStateSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.Footstep. + SurfaceTag) via GASP notify |
BPC_StateManager |
Dispatcher |
OnHeartRateChanged(BPM) → BPC_HapticsController::PlayHeartbeatHaptic(BPM) |
BPC_AccessibilitySettings |
Dispatcher |
OnHapticsToggleChanged(bEnabled) → BPC_HapticsController::SetHapticsEnabled() |
BPC_DeathHandlingSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.Death) on death |
BPC_DamageReceptionSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.Explosion) on area damage |
BPC_StaminaSystem |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.StaminaExhausted) on empty |
BPC_HealthSystem (low) |
Function Call |
BPC_HapticsController::PlayHapticByTag(Haptic.LowHealth) when <25% HP |
9. Validation / Testing Checklist
Initializecorrectly detects Xbox controller:CurrentPlatform = XboxInitializecorrectly detects PS5 DualSense:CurrentPlatform = PS5_DualSensePlayHapticByTagwith valid tag plays force feedback on controllerPlayHapticByTagwith invalid tag logs warning but does not crashStopHapticimmediately stops all controller vibrationbHapticsEnabled = falsecauses allPlayHapticByTagcalls to be skipped- Heartbeat haptic loops at correct interval (60 BPM → 1 pulse/second)
- Heartbeat BPM changes dynamically when
PlayHeartbeatHaptic(120)called - DualSense trigger resistance activates on PS5 (R2 stiffens when aiming)
- Non-DualSense platforms gracefully skip trigger effects (no crash, no log spam)
- Priority conflict: higher priority effect interrupts lower (damage overrides footstep)
MinTimeBetweenEffectsprevents rapid-fire rumble spam- Edge case:
PlayHapticByTagbeforeInitializelogs warning and returns - Edge case: Controller disconnected mid-effect —
StopHapticcalled safely - Edge case: Multiple rapid
PlayHapticByTagcalls — only highest priority plays - Edge case: Platform hot-swap (Xbox → PS5) fires
OnControllerPlatformChanged
10. Reuse Notes
- Attach this component to the Player Controller (not the Pawn). Haptics are per-controller, per-player.
- All gameplay systems trigger haptics via GameplayTag — never hardcode
Play Force Feedbacknodes. - The
DA_HapticProfileData Asset stores platform-specificUForceFeedbackEffectcurves. Designers author these in the Content Browser without touching Blueprints. - For multiplayer: haptics are local client only — never replicated. The server doesn't need to know about controller vibration.
- Heartbeat haptic is the only continuous/looping effect. All others are one-shot.
- DualSense adaptive triggers require the PS5 Controller Plugin enabled. Framework gracefully degrades on other platforms.
- The
Haptic.GameplayTag namespace is documented inDT_Tags_Player.csvandDA_GameTagRegistry. - Accessibility:
bHapticsEnabledsyncs withBPC_AccessibilitySettingsso players can disable all vibration from settings. - For platform profiles: create one
DA_HapticProfileinstance per event per platform, then reference all three in the profile map.BPC_HapticsControllerselects the right one at runtime.
11. Manual Implementation Guide
This section is for a human implementer building the Blueprint manually in UE5. Follow these steps in order. Each function is broken down into specific UE5 Blueprint nodes.
11.1 Class Setup
- Create a new Blueprint Class:
- Parent Class:
ActorComponent - Name:
BPC_HapticsController - Path:
Content/Framework/Settings/
- Parent Class:
- Add all variables from Section 3 to the Class Defaults.
- Configuration variables: set
Instance Editable✓ - Internal variables: set to
Private(no expose)
- Configuration variables: set
- Add the Event Dispatchers from Section 5.
11.2 Variable Initialization (BeginPlay)
Event BeginPlay
├─ Get Owner → Cast to PlayerController → Store as CachedPlayerController
│ └─ If NOT valid: Print String "BPC_HapticsController: Owner is not a PlayerController!" → Return
├─ Call DetectControllerPlatform → Set CurrentPlatform
├─ Load Asset Registry → Get All Assets of Class (DA_HapticProfile)
│ └─ ForEach: Add to HapticProfileMap [ProfileTag → Asset]
├─ Get Owner → Get Component by Class (BPC_AccessibilitySettings)
│ └─ If valid: Bind Event OnHapticsToggleChanged → SetHapticsEnabled
│ └─ If valid: Read initial bHapticsEnabled value
├─ Get Owner Pawn → Get Component by Class (BPC_StateManager)
│ └─ If valid: Bind Event OnHeartRateChanged → PlayHeartbeatHaptic
├─ Set bIsInitialized = true
└─ Call OnHapticsControllerInitialized
11.3 Function Implementations
PlayHapticByTag
Input Pins: ProfileTag (GameplayTag), IntensityMultiplier (Float)
Output Pins: None
Node-by-Node Logic:
[Function: PlayHapticByTag]
Step 1: Branch on bHapticsEnabled → False: Return
Step 2: Get Game Time in Seconds → Subtract LastPlayTime → Compare to MinTimeBetweenEffects
Branch → Too soon: Return (or queue if needed)
Step 3: HapticProfileMap → Find (ProfileTag) → Store as FoundProfile
Step 4: Branch on FoundProfile valid?
True →
Step 4a: Make S_HapticRequest:
- ProfileTag = ProfileTag
- EventType = FoundProfile.EventType
- IntensityMultiplier = IntensityMultiplier
- DurationOverride = -1 (use profile default)
- Priority = FoundProfile.Priority
Step 4b: Call PlayHapticInternal(S_HapticRequest)
Step 4c: Call OnHapticPlayed(ProfileTag, FoundProfile.EventType, IntensityMultiplier)
False →
Step 4d: Print String Warning: "No haptic profile found for tag: {ProfileTag}"
Nodes Used: Branch, FindGameplayTag, Map Find, Make Struct (S_HapticRequest), Call Function, Print String
PlayHapticInternal
Input Pins: Request (S_HapticRequest)
Output Pins: None
Node-by-Node Logic:
[Function: PlayHapticInternal]
Step 1: If ActiveHapticEffect is valid → Call StopHaptic (interrupt current)
Step 2: Break S_HapticRequest → get ProfileTag
Step 3: Look up DA_HapticProfile from HapticProfileMap
Step 4: Switch on CurrentPlatform:
Case PS5_DualSense: Get PS5_ForceFeedbackCurve from profile
Case Xbox: Get Xbox_ForceFeedbackCurve from profile
Default: Get Generic_ForceFeedbackCurve from profile
Step 5: Branch on selected curve valid?
True →
Step 5a: CachedPlayerController → Play Force Feedback
- Force Feedback Effect: selected curve asset
- Intensity Multiplier: Request.IntensityMultiplier * HapticIntensityScale
- bLooping: false
- bIgnore Time Dilation: true
Step 5b: Set ActiveHapticEffect = selected curve
False →
Step 5c: Print String Warning: "No ForceFeedbackEffect for platform {CurrentPlatform}"
Step 6: Set LastPlayTime = Get Game Time in Seconds
Nodes Used: Switch on EControllerPlatform, Break S_HapticRequest, Map Find, Play Force Feedback (PlayerController), Branch
PlayHeartbeatHaptic
Input Pins: BeatsPerMinute (Float)
Output Pins: None
Node-by-Node Logic:
[Function: PlayHeartbeatHaptic]
Step 1: Clamp (BeatsPerMinute, HeartbeatMinBPM, HeartbeatMaxBPM) → Store as ClampedBPM
Step 2: Divide 60.0 / ClampedBPM → Store as PulseInterval
Step 3: If bHeartbeatActive:
True → Clear Timer by Handle (HeartbeatTimerHandle)
Step 4: Set bHeartbeatActive = true
Step 5: Set Timer by Event:
- Event: Custom Event (HeartbeatPulse)
- Time: PulseInterval
- Looping: true
- Store handle as HeartbeatTimerHandle
[Custom Event: HeartbeatPulse]
→ Call PlayHapticByTag(Haptic.Heartbeat, 1.0)
Nodes Used: Clamp (float), Divide, Set Timer by Event, Clear Timer by Handle
SetHapticsEnabled
Input Pins: bEnabled (Bool)
Output Pins: None
[Function: SetHapticsEnabled]
Step 1: Set bHapticsEnabled = bEnabled
Step 2: Branch:
False → Call StopHaptic
Step 3: Call OnHapticsEnabledChanged(bEnabled)
DetectControllerPlatform
[Function: DetectControllerPlatform]
Step 1: Get Platform Name → Store as PlatformStr
Step 2: String Contains (PlatformStr, "PS5") → True: Set CurrentPlatform = PS5_DualSense → Return
Step 3: String Contains (PlatformStr, "PS4") → True: Set CurrentPlatform = PS4_DualShock → Return
Step 4: String Contains (PlatformStr, "Xbox") → True: Set CurrentPlatform = Xbox → Return
Step 5: Get Input Device Type → Switch on Type:
Gamepad → Set CurrentPlatform = PC_Generic
Default → Set CurrentPlatform = Unknown
Nodes Used: Get Platform Name, Contains (string), Switch on String, Get Input Device Type
11.4 Event Dispatcher Bindings (Inbound Listeners)
| Bind to Dispatcher | Custom Event to Create | What it Does |
|---|---|---|
BPC_StateManager.OnHeartRateChanged |
OnHeartRateChanged_Handler |
PlayHeartbeatHaptic(CurrentHeartRate) |
BPC_AccessibilitySettings.OnHapticsToggleChanged |
OnHapticsToggle_Handler |
SetHapticsEnabled(bEnabled) |
11.5 Multiplayer Networking
- This component is local client only. No replication needed.
- Haptics play only on the local player's controller.
- No
HasAuthority()gates needed — haptics are cosmetic. - For listen server hosts:
IsLocalPlayerController()check before playing effects.
11.6 Quick Node Reference
| Node | Where to Find | Used For |
|---|---|---|
Play Force Feedback |
Right-click → "Play Force Feedback" | Playing rumble effect on controller |
Stop Force Feedback |
Right-click → "Stop Force Feedback" | Stopping all active vibration |
Set Timer by Event |
Right-click → "Set Timer by Event" | Looping heartbeat pulse |
Get Platform Name |
Right-click → "Get Platform Name" | Detecting Xbox/PS5/PC |
Clamp (float) |
Right-click → "Clamp" | Clamping BPM range |
Make Struct |
Right-click → "Make S_HapticRequest" | Building haptic request |
Map Find |
Right-click → "Find" | Looking up profile by tag |
Get Game Time in Seconds |
Right-click → "Get Game Time" | Cooldown tracking |
12. Blueprint Build Checklist
- Create Blueprint class:
BPC_HapticsController(parent:ActorComponent) - Add all variables from Section 3 with correct types and defaults
- Create
EHapticEvent,EHapticMotor,EControllerPlatformenums (in Content Browser) - Create
S_HapticRequeststruct (in Content Browser) - Build
BeginPlayevent →Initializechain - Implement
DetectControllerPlatformfunction - Implement
PlayHapticInternalwith Platform Switch - Implement
PlayHapticByTag(public entry point) - Implement
PlayHapticByEvent(convenience wrapper) - Implement
StopHaptic/StopHeartbeatHaptic - Implement
PlayHeartbeatHapticwith looping timer - Implement
SetHapticsEnabled/SetDualSenseTriggerEffect - Create all 6 event dispatchers
- Bind to
BPC_StateManager.OnHeartRateChanged - Bind to
BPC_AccessibilitySettings.OnHapticsToggleChanged - Create at least one
DA_HapticProfileinstance forHaptic.Damage.Default - Test: PlayHapticByTag triggers vibration on Xbox controller
- Test: PlayHapticByTag triggers vibration on PS5 DualSense
- Test: bHapticsEnabled=false blocks all effects
- Test: Heartbeat BPM changes pitch/speed of pulse
- Test: Rapid-fire calls respect MinTimeBetweenEffects
Blueprint Spec: Haptics Controller. Conforms to TEMPLATE.md v2.0 — part of the UE5 Modular Game Framework, SETTINGS layer.